Cha*_*l72 10 c++ move-semantics c++11
在使用C++ 0x移动语义移动对象后,我对它的状态感到困惑.我的理解是,一旦一个对象被移动,它仍然是一个有效的对象,但它的内部状态已被改变,以便在调用它的析构函数时,不会释放任何资源.
但是,如果我的理解是正确的,一个移动的对象的析构函数应该仍然被调用.
但是,当我执行一个简单的测试时,这不会发生:
struct Foo
{
Foo()
{
s = new char[100];
cout << "Constructor called!" << endl;
}
Foo(Foo&& f)
{
s = f.s;
f.s = 0;
}
~Foo()
{
cout << "Destructor called!" << endl;
delete[] s; // okay if s is NULL
}
void dosomething() { cout << "Doing something..." << endl; }
char* s;
};
void work(Foo&& f2)
{
f2.dosomething();
}
int main()
{
Foo f1;
work(std::move(f1));
}
Run Code Online (Sandbox Code Playgroud)
这个输出:
Constructor called!
Doing something...
Destructor called!
Run Code Online (Sandbox Code Playgroud)
请注意,析构函数只被调用一次.这表明我的理解是关闭的.为什么析构函数不会被调用两次?这是我对应该发生的事情的解释:
Foo f1 是建造的.Foo f1传递给work,取一个右值f2.Foo被调用时,将所有的资源f1
来f2.f2调用析构函数,释放所有资源.f1调用了析构函数,因为所有资源都被转移到了,所以它实际上并没有做任何事情f2.尽管如此,仍然会调用析构函数.但由于只调用了一个析构函数,因此步骤4或步骤5都不会发生.我从析构函数中做了一个回溯,看看它是从哪里调用的,它是从第5步调用的.那么为什么f2析构函数也不会被调用呢?
编辑:好的,我修改了这个,所以它实际上是在管理一个资源.(内部内存缓冲区.)但是,我得到的结果是析构函数只被调用一次.
编辑 (新的和正确的答案)
抱歉,仔细看看代码,似乎答案更简单:你永远不会调用移动构造函数.你永远不会真正移动对象.您只需将rvalue引用传递给work函数,该函数调用该引用上的成员函数,该函数仍然指向原始对象.
原始答案,为子孙后代保存
为了实际执行移动,你必须有类似Foo f3(std::move(f2));内部的东西work.然后你可以调用你的成员函数,f3它是一个新的对象,通过移动来创建f
据我所知,你根本没有移动语义.你只是看到普通的旧版复制品.
要使移动发生,你必须使用std::move(或者特别是,传递给构造函数的参数必须是一个未命名的/临时的)右值引用,例如从中返回的引用std::move.否则它被视为一个普通的老式左值引用,然后应该发生一个副本,但是像往常一样,允许编译器优化它,留下你正在构造一个对象,并且一个对象被销毁.
无论如何,即使使用移动语义,也没有理由为什么编译器不应该做同样的事情:只是优化移动,就像它已经优化了副本一样.移动很便宜,但是只需构建一个需要它的对象,而不是构造一个,然后将其移动到另一个位置并在第一个位置调用析构函数,它仍然更便宜.
值得注意的是,你使用的是相对较旧的编译器,早期版本的规范还不清楚这些"僵尸对象"会发生什么.所以GCC 4.3可能不会调用析构函数.我相信它只是最后一个版本,或者也许是它之前的版本,明确要求调用析构函数
| 归档时间: |
|
| 查看次数: |
2732 次 |
| 最近记录: |