конструктор перемещения не вызывается должным образом

Я новичок в C ++ 0x и пытаюсь обернуть голову вокруг ссылок на rvalue и переместить конструкторы. Я использую g ++ 4.4.6 с -std = c ++ 0x, и меня смущает следующий фрагмент кода:



class Foo
{
public:
Foo()
: p( new int(0) )
{
printf("default ctor\n");
}

Foo( int i )
: p( new int(i) )
{
printf("int ctor\n");
}

~Foo()
{
delete p;
printf("destructor\n");
}

Foo( const Foo& other )
: p( new int( other.value() ) )
{
printf("copy ctor\n");
}Foo( Foo&& other )
: p( other.p )
{
printf("move ctor\n");
other.p = NULL;
}

int value() const
{
return *p;
}

private:
// make sure these don't get called by mistake
Foo& operator=( const Foo& );
Foo& operator=( Foo&& );

int* p;
};Foo make_foo(int i)
{
// create two local objects and conditionally return one or the other
// to prevent RVO
Foo tmp1(i);
Foo tmp2(i);

// With std::move, it does indeed use the move constructor
//  return i ? std::move(tmp1) : std::move(tmp2);
return i ? tmp1 : tmp2;

}int main(void)
{
Foo f = make_foo( 3 );

printf("f.i is %d\n", f.value());

return 0;
}

Я обнаружил, что, как написано, компилятор использует конструктор копирования для построения объекта в main (). Когда я использую строку std :: move внутри make_foo (), тогда конструктор перемещения используется в main (). Почему std :: move необходим внутри make_foo ()? Я думаю, что хотя tmp1 и tmp2 являются именованными объектами внутри make_foo (), когда они возвращаются из функции, они должны стать временными.

14

Решение

Это ваша проблема:

return i ? tmp1 : tmp2;

Локальная переменная в функции будет перемещена из оператора return, только если оператор return return var;, Если вы хотите выполнить этот тест, вам нужно использовать if:

if (i) {
return tmp1;
} else {
return tmp2;
}

Цитата немного запутанная, но в 12.8 / 31 и 12.8 / 32

12.8 / 32 Когда критерии для исключения операции копирования будут выполнены или будут выполнены, за исключением того факта, что исходный объект является параметром функции, а копируемый объект обозначается lvalue, разрешение перегрузки для выбора конструктора для копия сначала выполняется, как если бы объект был обозначен rvalue […]

То есть, даже если выражение является lvalue, оно будет считаться rvalue при выполнении критериев в 12.8 / 31, второй вариант в этом блоке:

12.8 / 31 в операторе return в функции с типом возврата класса, когда выражение является именем энергонезависимого автоматического объекта (кроме параметра функции или предложения catch) с тем же типом cv-unqualified, что и функция возвращаемый тип, операция копирования / перемещения может быть опущена путем создания автоматического объекта непосредственно в возвращаемое значение функции.

Что определяет, что return tmp; позволяет копировать исключение, но return (cond?tmp:tmp); не делает.

Обратите внимание, что для компилятора для генерации неявного std::move в операторе return возвращаемый объект должен быть кандидатом на elision, если только он не является аргументом функции. Использование условной операции запрещает копирование, и в то же время запрещает компилятору перемещаться из ваших объектов. Этот второй случай может быть проще для кода:

Foo make_foo(Foo src) {
return src;           // Copy cannot be elided as 'src' is an argument
}
11

Другие решения

Других решений пока нет …

По вопросам рекламы ammmcru@yandex.ru
Adblock
detector