我正在准备关于复制构造函数的讲座,并发现了这个:
MyClass myFunction()
{
MyClass mc;
return mc;
}
声明说:
如果我们调用myFunction,那么C ++将创建一个新的myClass对象 当myFunction返回时,它被初始化为mc。这样你的代码 可能会像透明地从内部移动物体一样 myFunction到你的其余代码,它实际上是临时的 副本。
我认为声明MyClass mc;将创建对象并返回表单函数而不是任何临时对象。 我哪里错了?有人可以说明这个陈述能够轻易理解吗?
答案 0 :(得分:3)
我认为声明MyClass mc;将创建对象
正确。
它返回表单函数而不是任何临时对象。
我不完全理解你的陈述,所以我不知道你是否出错,但这就是:
mc
是一个局部变量。函数退出时会破坏局部变量。在销毁之前,会从中复制初始化临时对象。然后从函数返回临时对象。
额外知识1:从C ++ 11开始,如果可能,临时由 move 进行复制初始化。
额外知识2:标准明确允许编译器跳过复制/移动,而是在调用站点构造对象。此优化称为(命名)返回值优化,是一种复制省略。尽管如此,您仍然无法返回既不可复制也不可移动的对象。这是因为不需要使用C ++实现NRVO。
答案 1 :(得分:1)
假设你有这段代码:
#include <iostream>
using namespace std;
class MyClass
{
public:
int *v;
MyClass()
{
v=new int[5];
for(int i=0;i<5;i++) v[i]=i; // x will look like : 0,1,2,3,4
}
~MyClass()
{
cout<<"Destructor called! Now v is deallocated! \n";
delete[] v;
}
};
MyClass myFunction()
{
MyClass mc;
return mc;
}
int main()
{
MyClass x;
x=myFunction();
cout<<x.v[2]<<'\n'; //it may or may not print the right thing
return 0;
}
如您所见,myFunction
像您所说的那样返回对象mc
。但是你也知道mc
的析构函数将在mc
超出范围时被调用 - mc
在myFunction
内被声明,因此析构函数将在函数后被调用执行并释放内存(delete[] v
)。内存被释放,但值仍然存在于内存中!所以,即使x=myFunction();
可行,你也会有一个内存v指向的对象被释放!因此,cout<<x.v[2]<<'\n';
可能无法打印正确的内容。如果你编译代码,可能打印正确的值(2),因为内存没有被覆盖,但如果你在cout语句之前或者在使用你的一段时间后再做一些分配操作系统,您将看到打印的值不正确/崩溃,因为内存将被其他程序覆盖。 v
仍然指向那个内存块,但它不知道那里有什么,因为内存被释放了。
内部myFunction
:v - &gt; |0|1| 2 |3|4|...
退出myFunction
后:v - &gt; |0|1| 2 |3|4|.....
经过一些内存分配后:v - &gt; |a|1| b |@|%|3|7|2|1|*|!|......