我对你的问题感兴趣,因为我对这个话题很陌生并且做了一些研究。
让我介绍一下结果。
首先是你的叹息。
::叹息:: C++0x 应该让我编写更少的代码,而不是更多!
它还应该让您更好地控制代码。确实如此。
我会坚持使用额外的构造函数:
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}
我个人更喜欢在复杂而重要的情况下使用冗长的内容,因为它让我和可能的代码读者保持警惕。
以 C 风格的演员为例(T*)pT
和C++标准static_cast<T*>(pT)
更加冗长 - 但向前迈出了一大步。
其次,我对你的示例 3(最后一个测试用例)有点怀疑。我认为可能涉及另一个移动构造函数来从右值创建按值传递参数。所以我在我的新 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);
}
正如您所指出的,有一个编译时开关允许我测试这两种方法。
结果 http://ulysses.in.ua/cmp.GIF最好在文本比较模式下查看,在左侧您可以看到#if 1
编译,这意味着我们检查建议的解决方法,在右侧 -#if 0
,这意味着我们检查 c++0x! 中描述的“kosher”方式。
我错误地怀疑编译器做了愚蠢的事情;它在第三个测试用例中保存了额外的移动构造函数。
但说实话,我们必须考虑到在建议的解决方法中调用了另外两个析构函数,但这肯定是一个小缺点,因为如果被破坏的对象发生移动,则不应执行任何操作。不过,很高兴知道这一点。
无论如何,我不会留下这样的观点:最好在包装类中编写另一个构造函数。这只是几行的问题,因为所有繁琐的工作已经在SomeClass
that has有一个移动构造函数。