我在理解C++中返回值背后真正做了些什么困难。返回值(引用,指针和对象)
让我们下面的代码:
class MyClass {
public:
int id;
MyClass(int id) {
this->id = id;
cout << "[" << id << "] MyClass::ctor\n";
}
MyClass(const MyClass& other) {
cout << "[" << id << "] MyClass::ctor&\n";
}
~MyClass() {
cout << "[" << id << "] MyClass::dtor\n";
}
MyClass& operator=(const MyClass& r) {
cout << "[" << id << "] MyClass::operator=\n";
return *this;
}
};
MyClass foo() {
MyClass c(111);
return c;
}
MyClass& bar() {
MyClass c(222);
return c;
}
MyClass* baz() {
MyClass* c = new MyClass(333);
return c;
}
我使用gcc 4.7.3。
案例1
当我打电话:
MyClass c1 = foo();
cout << c1.id << endl;
输出是:
[111] MyClass::ctor
111
[111] MyClass::dtor
我的理解是,在foo
对象是在栈上创建,然后在销毁返回语句,因为它是范围的结尾。返回是通过对象复制(复制构造函数)完成的,稍后将其分配给主(赋值运算符)中的c1
。如果我是正确的,为什么没有复制构造函数或赋值运算符的输出?这是因为RVO吗?
案例2
当我打电话:
MyClass c2 = bar();
cout << c2.id << endl;
输出是:
[222] MyClass::ctor
[222] MyClass::dtor
[4197488] MyClass::ctor&
4197488
[4197488] MyClass::dtor
这到底是怎么回事?我创建变量然后返回它,变量被销毁,因为它是一个范围的结束。编译器试图通过拷贝构造函数拷贝该变量,但它已经被销毁,这就是为什么我有随机值?那么主要在c2
究竟是什么?
案例3
当我打电话:
MyClass* c3 = baz();
cout << c3->id << endl;
输出是:
[333] MyClass::ctor
333
这是最简单的情况?我返回一个动态创建的指针,位于堆上,所以memmory被分配,而不是自动释放。当析构函数没有被调用并且我有内存泄漏时,就是这种情况。我对吗?
是否还有其他不明显的情况或事情,我应该知道要充分掌握C++中的返回值? ;)从函数返回一个对象的建议方法是什么(如果有的话) - 对此的任何经验规则?
'MyClass c1 = foo();'不是一个赋值。这是一个*复制初始化*。 – dyp
嗯,我的错。所以在所有这些情况下'operator ='不会被调用? – jesper
确实。经验法则:除非你想暴露内部(像'std :: vector :: operator []'返回一个引用),否则不要返回拥有的原始指针(即一个必须被删除的),不要返回一个const对象(因为它禁止了移动语义)。 – dyp