我刚刚听完了Scott Meyers关于C++ 0x的软件工程电台播客采访.大多数新功能对我来说都很有意义,我现在对C++ 0x感到兴奋,除了一个.我仍然没有得到移动语义 ......它们究竟是什么?
unique_ptr<T>不允许复制构造,而是支持移动语义.然而,我可以unique_ptr<T>从函数返回一个并将返回的值赋给变量.
#include <iostream>
#include <memory>
using namespace std;
unique_ptr<int> foo()
{
unique_ptr<int> p( new int(10) );
return p; // 1
//return move( p ); // 2
}
int main()
{
unique_ptr<int> p = foo();
cout << *p << endl;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
上面的代码按预期编译和工作.那么该行如何1不调用复制构造函数并导致编译器错误呢?如果我必须使用line 2而不是它有意义(使用line 2也可以,但我们不需要这样做).
我知道C++ 0x允许此异常,unique_ptr因为返回值是一个临时对象,一旦函数退出就会被销毁,从而保证返回指针的唯一性.我很好奇这是如何实现的,它是在编译器中特殊的,还是在语言规范中有一些其他条款可以利用?
标准是否准确定义了对象移动后我可以对其做什么?我曾经认为你用移动物体做的所有事情都可以破坏它,但这还不够.
例如,采用swap标准库中定义的函数模板:
template <typename T>
void swap(T& a, T& b)
{
T c = std::move(a); // line 1
a = std::move(b); // line 2: assignment to moved-from object!
b = std::move(c); // line 3: assignment to moved-from object!
}
Run Code Online (Sandbox Code Playgroud)
显然,必须可以分配给移动的对象,否则第2行和第3行将失败.那么移动对象我还能做些什么呢?我在哪里可以找到标准中的这些细节?
(顺便说一句,为什么它T c = std::move(a);不是T c(std::move(a));第1行呢?)
我基本上想弄清楚,整个"移动语义"概念是一些全新的,还是只是让现有的代码更容易实现?我总是对减少调用复制/构造函数的次数感兴趣,但我通常使用引用(可能是const)传递对象,并确保我总是使用初始化列表.考虑到这一点(并考虑了整个丑陋的&&语法),我想知道是否值得采用这些原则或者只是按照我已经做的编码?这里有什么新东西要做,还是我已经做过的"更容易"的语法糖?
我试着通过阅读这篇博客来了解零的规则.IMO,它说如果你声明自己的析构函数,那么不要忘记创建移动构造函数并将赋值移动为默认值.
示例:
class Widget {
public:
~Widget(); // temporary destructor
... // no copy or move functions
};
Run Code Online (Sandbox Code Playgroud)
"添加析构函数会产生禁用生成移动函数的副作用,但由于Widget是可复制的,因此用于生成移动的所有代码现在都会生成副本.换句话说,向类中添加析构函数可能会导致 - 有效的动作可以用可能效率低下的副本无声地替换".
Scott Meyers的上述文字在引言中提出了一些问题:
什么是值语义和引用语义,它们之间有什么区别?你能用c中的例子给我看看吗?
我猜在引用语义中,你只是发送一个指向另一个函数的指针,然后它是引用语义?我发现很难理解什么是值语义?如果我只使用 int 作为参数,然后假设从该函数返回一个 int,那么该函数使用值语义?副作用如何影响这一点?肯定还有其他值语义的例子,然后我提到了我是否正确。你能给我举个例子吗?如果函数将指针作为参数并且函数返回值是 int,那么该函数是否同时使用了引用语义和值语义?
c++ ×5
c++11 ×5
c ×1
c++-faq ×1
destructor ×1
move ×1
optimization ×1
performance ×1
reference ×1
return-value ×1
rule-of-zero ×1
semantics ×1
swap ×1
unique-ptr ×1