dea*_*ean 49 c++ rvalue-reference move-semantics c++11
看来关于C++ 0x的rvalues的主要建议是添加移动构造函数并将运算符移动到类中,直到编译器默认实现它们.
但是如果使用VC10,等待是一种失败的策略,因为自动生成可能不会在VC10 SP1之前,或者在最坏的情况下,VC11.可能,等待这个将是多年来衡量.
这就是我的问题.编写所有这些重复的代码并不好玩.这看起来很不愉快.但对于那些认为很慢的课程来说,这是一个很受欢迎的负担.对于数百个(如果不是数千个)较小的类而言,情况并非如此.
::叹气:: C++ 0x应该让我写更少的代码,而不是更多!
然后我有了一个想法.很多人都愿意共享,我猜.
为什么不按价值传递一切?不会std :: move + copy elision使这几乎达到最佳状态吗?
OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
SomeClass o;
OurClass(o); // single copy
OurClass(std::move(o)); // single copy
OurClass(SomeClass()); // single copy
Run Code Online (Sandbox Code Playgroud)
缺点: rvalues的浪费副本.
OurClass::OurClass(const SomeClass& obj) : obj(obj) {}
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}
SomeClass o;
OurClass(o); // single copy
OurClass(std::move(o)); // zero copies, one move
OurClass(SomeClass()); // zero copies, one move
Run Code Online (Sandbox Code Playgroud)
优点:大概是最快的.
缺点:很多代码!
OurClass::OurClass(SomeClass obj) : obj(std::move(obj)) {}
SomeClass o;
OurClass(o); // single copy, one move
OurClass(std::move(o)); // zero copies, two moves
OurClass(SomeClass()); // zero copies, one move
Run Code Online (Sandbox Code Playgroud)
优点:没有其他代码.
缺点:在案例1和案例2中浪费了移动.如果SomeClass没有移动构造函数,性能将受到很大影响.
你怎么看?它是否正确?与代码减少的好处相比,产生的移动是否是普遍可接受的损失?
我对你的问题感兴趣,因为我对这个主题不熟悉并做了一些研究.让我介绍一下结果.
首先,你的叹息.
::叹气:: C++ 0x应该让我写更少的代码,而不是更多!
它也应该是为了让你更好地控制代码.它确实如此.我会坚持一个额外的构造函数:
OurClass::OurClass(SomeClass&& obj) : obj(std::move(obj)) {}
Run Code Online (Sandbox Code Playgroud)
我个人更喜欢在复杂和重要的情况下的冗长,因为它让我和我的代码的可能读者得到警报.
例如,采用C风格的演员(T*)pT和C++标准static_cast<T*>(pT)
更加冗长 - 但是向前迈出了一大步.
其次,我对你的例3,最后一个测试用例有点怀疑.我认为可能有另一个移动构造函数来从rvalue创建pass-by-value参数.所以我在我的新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){
}
Run Code Online (Sandbox Code Playgroud)
请注意这个部分:
#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
Run Code Online (Sandbox Code Playgroud)
...
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);
}
Run Code Online (Sandbox Code Playgroud)
正如您所指出的,有一个编译时开关允许我测试这两种方法.
结果最好在文本比较模式下查看,左边你可以看到#if 1编译,这意味着我们检查建议的解决方法,在右边 - #if 0意味着我们检查c ++ 0x中描述的"kosher"方式!
我怀疑编译器做了蠢事我错了; 它在第三个测试用例中保存了额外的移动构造函数.
但说实话,我们必须考虑在建议的解决方法中调用另外两个析构函数,但考虑到如果在被破坏的对象上发生移动则不应执行任何操作,这肯定是一个小缺点.不过,很高兴知道.
无论如何,我不是说在包装类中编写另一个构造函数更好.这只是几行问题,因为所有繁琐的工作已经完成SomeClass,必须有一个移动构造函数.
| 归档时间: |
|
| 查看次数: |
2960 次 |
| 最近记录: |