我正在尝试理解C ++ 11中的移动语义,并且我编写了一小段代码来检查在创建对象时调用哪些构造函数。
这是代码:
#include <iostream>
using namespace std;
class Bar
{
public:
int b;
Bar();
Bar(const Bar&);
~Bar();
};
class Foo
{
public:
int d;
Bar* b;
Foo();
Foo(const Foo&);
Foo(Foo&& other);
~Foo();
Foo& operator = (Foo);
};
Foo test();
Foo::Foo()
{
cout << "Default ctr of foo called\n";
b = new Bar();
}
Foo::~Foo()
{
delete b;
}
Foo::Foo(const Foo& other)
{
cout << "Copy ctr of foo called\n";
d = other.d;
b = new Bar();
b->b = other.b->b;
}
Foo::Foo(Foo&& other)
{
cout << "Move ctr of foo called\n";
d = other.d;
b = other.b;
other.d = 0;
other.b = NULL;
}
Foo& Foo::operator = (Foo other)
{
cout << "Copy assignment of foo called\n";
d = other.d;
b = new Bar();
b->b = other.b->b;
return *this;
}
Bar::Bar()
{
b = 1;
}
Bar::~Bar()
{
}
Bar::Bar(const Bar& other)
{
b = other.b;
}
int main()
{
Bar b;
Foo f1;
Foo f = test();
Foo f3 = move(test());
// cout << f1.b->b << "\n";
// Foo f2(test());
return 0;
}
Foo test()
{
Foo f;
return f;
}
这是我得到的输出:
Default ctr of foo called
Default ctr of foo called
Default ctr of foo called
Move ctr of foo called
我不明白为什么没有为Foo f调用移动构造函数。是不是test()是一个右值?在这种情况下调用哪个构造函数?
非常感谢任何帮助。
答案 0 :(得分:5)
你在这里看到的是复制省略的效果。复制省略是标准指定的优化,它使编译器在从堆栈返回对象的情况下,使函数在调用者的堆栈空间中构建对象并绕过复制并完全移动构造函数,无论副作用。在您的情况下,副作用是构造函数打印到cout
的内容。
我们可以通过使用例如unique_ptr
来在堆上创建对象来阻止编译器使用此快捷方式。它涉及的更多,但它可以得到你期望的结果:
#include <unique_ptr>
Foo test()
{
unique_ptr<Foo> f(new Foo);
return move(*f);
}
在这种情况下,您需要移动f
的指针,因为unique_ptr
的{{1}}返回引用,而不是临时引用。如果你不移动它,它将调用复制构造函数。