Меня заинтересовал ваш вопрос, потому что я был новичком в этой теме и провел некоторое исследование.
Позвольте мне представить результаты.
Сначала твой вздох.
:: sighs :: C ++ 0x должен был позволить мне писать меньше кода, а не больше!
также предполагается, что вы дадите вам лучший контроль над кодом. И это так.
Я хотел бы придерживаться дополнительного конструктора:
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}
Лично я предпочитаю многословие в сложных и важных ситуациях, потому что это предупреждает меня и возможных читателей моего кода.
возьмите, например, приведение в стиле C (T*)pT
и стандарт C ++ static_cast<T*>(pT)
Гораздо более многословный - но большой шаг вперед.
Во-вторых, я немного подозрительно относился к вашему Примеру 3, последнему тестовому примеру. Я подумал, что может быть другой конструктор перемещения, задействованный для создания переданного по значению параметра из значения rvalue. Итак, я создал небольшой проект в своем новом VS2010 и получил некоторые разъяснения. Я опубликую здесь код и результаты.
источник:
// test.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <utility>
#include <iostream>
class SomeClass{
mutable int *pVal;
public:
int Val() const { return *pVal; };
SomeClass(int val){
pVal = new int(val);
std::cout << "SomeClass constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
}
SomeClass(const SomeClass& r){
pVal = new int(r.Val());
std::cout << "SomeClass copy constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
}
SomeClass(const SomeClass&& r){
pVal = r.pVal;
r.pVal = 0;
std::cout << "SomeClass move constructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
}
~SomeClass(){
if(pVal)
delete pVal;
std::cout << "SomeClass destructor(pVal = 0x" << std::hex << pVal << std::dec << ")" << std::endl;
}
};
class OtherClass{
SomeClass sc;
public:
OtherClass(int val):sc(val){
}
Обратите внимание на этот раздел:
#if 1
OtherClass(SomeClass r):sc(std::move(r)){
}
#else
OtherClass(const SomeClass& r):sc(r){
}
OtherClass(const SomeClass&& r):sc(std::move(r)){
}
#endif
...
int Val(){ return sc.Val(); }
~OtherClass(){
}
};
#define ECHO(expr) std::cout << std::endl << "line " << __LINE__ << ":\t" #expr ":" << std::endl; expr
int _tmain(int argc, _TCHAR* argv[])
{
volatile int __dummy = 0;
ECHO(SomeClass o(10));
ECHO(OtherClass oo1(o));
__dummy += oo1.Val();
ECHO(OtherClass oo2(std::move(o)));
__dummy += oo2.Val();
ECHO(OtherClass oo3(SomeClass(20)));
__dummy += oo3.Val();
ECHO(std::cout << __dummy << std::endl);
ECHO(return 0);
}
Как вы заметили, есть переключатель времени компиляции, который позволяет мне протестировать два подхода.
Результаты лучше всего просматривать в режиме сравнения текста, слева вы можете увидеть компиляцию #if 1
, что означает, что мы проверяем предложенный обходной путь, а справа - #if 0
, что означает, что мы проверяем «кошерный» способ, описанный в c ++ 0x!
Я был неправ, подозревая, что компилятор делает глупости; он сохранил дополнительный конструктор перемещения в третьем тестовом примере.
Но, честно говоря, мы должны учитывать еще два деструктора, вызываемых в предлагаемом обходном пути, но это, безусловно, незначительный недостаток, учитывая, что никакие действия не должны выполняться, если на разрушаемом объекте произошло движение , Тем не менее, это полезно знать.
В любом случае я не ухожу от того, что лучше написать еще один конструктор в классе оболочки. Это всего лишь несколько строк, так как вся утомительная работа в SomeClass
, которую имеет , имеет конструктор перемещения.