[英]C++: Execution of programm(constructors, destructors, assignment operators, etc)
我试图理解为什么以下C ++程序输出其功能。
#include <iostream>
#include <vector>
#include <initializer_list>
#include <memory.h>
using namespace std;
// Constructors and memory
class Test{
static const int SIZE = 100;
int *_pBuffer;
public:
Test(){
cout << "constructor" << endl;
_pBuffer = new int[SIZE]{}; // allocated memory for int[size] and initialised with 'size' 0's
}
Test(int i){
cout << "parameterized constructor" << endl;
_pBuffer = new int[SIZE]{};
for(int i=0; i<SIZE; i++)
{
_pBuffer[i] = 7*i;
}
}
Test(const Test& other) // in the copy constructor we...
{
cout << "copy constructor" << endl;
_pBuffer = new int[SIZE]{}; // allocate the bytes then copy them from the 'other'
memcpy(_pBuffer, other._pBuffer, SIZE*sizeof(int));
}
Test &operator=(const Test &other){
cout << "assignment" << endl;
_pBuffer = new int[SIZE]{}; // allocate the bytes then copy them from the 'other'
memcpy(_pBuffer, other._pBuffer, SIZE*sizeof(int));
return *this;
}
~Test(){
cout << "Destructor" << endl;
delete [] _pBuffer;
}
};
ostream &operator<<(ostream &out, const Test &test)
{
out << "Hello from test";
return out;
}
Test getTest()
{
return Test();
}
int main() {
Test test1 = getTest(); // object gets created with default constructor =>
cout << test1 << endl;
vector<Test> vec;
vec.push_back(Test());
return 0;
}
这是我期望的工作方式以及期望的打印方式:
Test test1 = getTest();
我期望在这里发生这种情况:在getTest内,使用ctor创建了一个Test实例,因此没有任何参数:cout <<构造函数; 然后,该值被返回并用'='分配给test1,在这种情况下,该值将是'copy ctor',因此也是cout <<'copy ctor';
cout << test1 << endl;
在这里,我期望cout <<“来自测试的Hello”; 重载的'<<'的cuz
vector<Test> vec;
vec.push_back(Test());
在这里,我期望创建一个实例,并使用no参数ctor将其推入vec(1),所以cout <<“” Constructor“ << endl;
然后我期望test1和vec(1)在程序结束时超出范围,所以2x“ cout <<” destructor“;”
因此,总体而言,我的期望是:
cout << constructor;
cout << copy constructor;
cout << hello from test;
cout << constructor;
cout << destructor;
cout << destructor;
但是程序的实际输出是这样的:
constructor
Hello from test
constructor
copy constructor
Destructor
Destructor
Destructor
这与我的期望不同:)。
在这些中,我想我可以理解我最终得到的额外析构函数。 我想当函数getTest()返回一个分配给test1的值时,该值也会在程序结尾处被销毁,这就是为什么需要额外的析构函数的原因。 或者至少我是这样认为的。 如果我错了,请纠正我。
我也不明白为什么我在第一个'cout <<“ Constructor”;之后没有得到'cout <<“ Copy ctor”'。 不是测试test1 = getTest();' 呼叫复制ctor?
另外,如果可能的话,请帮助我理解该程序的流程,以便我理解为什么它输出其功能并更好地理解c ++中的OOP。 感谢您的阅读。
此行为是由于复制省略 。 从标准§[class.copy]¶31:
当满足某些条件时,即使为复制/移动操作选择的构造函数和/或对象的析构函数具有副作用,也允许实现忽略类对象的复制/移动构造。 在这种情况下,实现将忽略的复制/移动操作的源和目标视为引用同一对象的两种不同方式,并且该对象的销毁发生在两个对象本来应该以较晚的时间发生。没有优化就销毁。 在以下情况下允许复制/移动操作的这种省略,称为复制删除(可以合并以消除多个副本):
[...]
—当尚未绑定到引用(12.2)的临时类对象将被复制/移动到具有相同cv-unqualtype类型的类对象时,可以通过将临时对象直接构造为以下形式来省略复制/移动操作:省略的复制/移动目标[...]
在这种情况下, Test test1 = getTest()
满足我上面引用的条件。 将在getTest
创建的临时Test
对象未绑定到引用。 因此,可以直接在getTest
的返回值中getTest
。 此优化也称为返回值优化或RVO。 同样,由于getTest
的返回值(本身是一个临时对象)未绑定到引用,因此可以直接将其构造到test1
。
对于vec.push_back(Test());
,您创建的临时Test
对象必须复制或移动到vector
的内部存储中。 在这种情况下,无法进行复制省略,因为您创建的临时对象在传递给push_back
时将绑定到引用,并且标准中列出的其他情况均不适用。 这意味着必须创建两个Test
对象:一个(使用您的临时对象)使用其默认构造函数构造,以及另一个(副本的vector
)由copy-constructor创建。
所以这是程序的实际输出。 我禁用了编译器优化并优化了返回值。 以下是程序的输出
constructor
copy constructor
Destructor
copy constructor
Destructor
Hello from test
constructor
copy constructor
Destructor
Destructor
Destructor
让我们分解一下。 第一个构造函数,复制和析构函数调用均与getTest()
方法相关。 当您通过Test()
创建对象实例时,最初会调用constructor
这将输出constructor
。 然后需要返回该值,因为所有这些都已编译成汇编对象,需要放置在堆栈上,尤其是需要放置在函数调用堆栈之前的位置(在之前或之后我可能是错误的)但是,在此之后保留一个位置作为返回值)。 因此,实例被复制到堆栈上的那个位置,并输出copy constructor
。 这导致函数完成并调用创建的原始实例的析构函数。
接下来是Test test1 = getTest();
然后,将函数调用中保留位置处的实例复制到变量test1
从而生成copy constructor
,然后保留位置处的实例将销毁,并输出Destructor
。
然后显示Hello from test
的Hello from test
,由于流运算符使用引用,因此不会复制任何内容。 因此,不会调用任何构造函数或析构函数。
当vec.push_back(Test());
时输出最后一个constructor
调用vec.push_back(Test());
专门称为Test()
。 创建此实例后,向量类将在push_back
调用期间将该实例复制到向量类的数组中的某个位置。 剩下的三个析构函数将调用test1
,在push_back
期间创建的实例以及存储在vector类中的实例。
希望对您有所帮助。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.