В последнее время я думал о хранении лямбда-выражений C ++. Стандартный совет, который вы видите в Интернете, - хранить лямбду в объекте std :: function. Однако ни один из этих советов никогда не рассматривает последствия для хранения. Мне пришло в голову, что за кулисами должно происходить какое-то серьезное вуду, чтобы это сработало.Рассмотрим следующий класс, который хранит целочисленное значение:
class Simple {
public:
Simple( int value ) { puts( "Constructing simple!" ); this->value = value; }
Simple( const Simple& rhs ) { puts( "Copying simple!" ); this->value = rhs.value; }
Simple( Simple&& rhs ) { puts( "Moving simple!" ); this->value = rhs.value; }
~Simple() { puts( "Destroying simple!" ); }
int Get() const { return this->value; }
private:
int value;
};
Теперь рассмотрим эту простую программу:
int main()
{
Simple test( 5 );
std::function<int ()> f =
[test] ()
{
return test.Get();
};
printf( "%d\n", f() );
}
Это результат, который я надеюсь увидеть в этой программе:
Constructing simple!
Copying simple!
Moving simple!
Destroying simple!
5
Destroying simple!
Destroying simple!
Сначала мы создаем тест значения. Мы создаем локальную копию в стеке для временного лямбда-объекта. Затем мы перемещаем временный лямбда-объект в память, выделенную std :: function. Уничтожаем временную лямбду. Распечатываем наш вывод. Уничтожаем std :: function. И наконец, уничтожаем тестовый объект.
Излишне говорить, что это не то, что я вижу. Когда я компилирую это в Visual C ++ 2010 (в режиме выпуска или отладки), я получаю следующий результат:
Constructing simple!
Copying simple!
Copying simple!
Copying simple!
Copying simple!
Destroying simple!
Destroying simple!
Destroying simple!
5
Destroying simple!
Destroying simple!
Черт побери, это неэффективно! Компилятор не только не смог использовать мой конструктор перемещения, но и сгенерировал и уничтожил две явно лишние копии лямбды во время присваивания.
Итак, вот наконец вопросы: (1) Действительно ли все это копирование необходимо? (2) Есть ли способ заставить компилятор генерировать лучший код? Спасибо за прочтение!