在尝试通过'按值传递'和随后的破坏来试验复制构造时,我尝试了这段代码:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Rock{
int sz;
public:
Rock():sz(0){cout<< "Default ctor"<<endl;}
~Rock(){cout<< "Dtor"<<endl;}
Rock(const Rock& r){ cout << "Copy ctor" << endl; sz = r.sz;}
Rock& operator=(const Rock& r) {cout << "In assignment op" << endl; sz = r.sz;}
};
int main()
{
vector<Rock> rocks;
Rock a, b, c;
rocks.push_back(a);
rocks.push_back(b);
rocks.push_back(c);
return 0;
}
得到以下输出。一直到第7行都很好,但是我无法理解从那时起会发生什么。有人可以澄清吗?
Default ctor
Default ctor
Default ctor
Copy ctor
Copy ctor
Copy ctor // all fine I got it...
Dtor
Copy ctor
Copy ctor
Copy ctor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
答案 0 :(得分:3)
让我们将输出关联到相应的代码行。
Rock a, b, c;
Default ctor
Default ctor
Default ctor
那个你可能已经想到了自己。 : - )
rocks.push_back(a);
Copy ctor
同样,你可能正确地想出来了。
rocks.push_back(b);
Copy ctor
Copy ctor // all fine I got it...
Dtor
您的评论显然是错误的,因为您几乎肯定不将两个构造函数调用与此语句关联: - )
当添加a
的副本时,该向量仅分配了足够的内存来存储a
的一个副本(它将被允许分配)更多,但)。因此,它必须分配一个足够大的新内存块来保存a
和 b
的副本,复制{{1}的副本它存储在旧内存块中,然后复制到新内存块,然后复制a
,然后在释放(现在不再需要)原始内存块之前销毁b
的原始副本。
a
从上面的解释,你现在应该可以猜出这里发生了什么。
但是请注意,如果你将另一个元素推回到向量中,很可能你再次得到一个复制构造函数而没有析构函数调用。这是因为向量的典型策略是在每个步骤中将分配的内存加倍,因此当推回rocks.push_back(c);
Copy ctor
Copy ctor
Copy ctor
Dtor
Dtor
时,它最有可能为4个对象分配空间。实际上c
需要使用指数策略(不需要使用因子2,并且有人认为黄金均值是一个更好的因素)。
std::vector
此处三个对象}
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
,c
,b
,然后向量中的三个对象被破坏。
答案 1 :(得分:1)
每当std::vector
必须增加其容量时(因为您要推送更多元素),它需要分配新存储,将所有现有元素从旧存储复制到新存储,然后删除旧元素。因此,您将获得对复制构造函数和析构函数的“额外”调用。
如果您在对cout
的每次通话之间加上push_back
声明,则应该有助于说明哪些ctor / dtor通话与每个push_back
相关联。
但这是我对年表的猜测:
Default ctor
Default ctor
Default ctor
// First push_back() (capacity initially 1)
Copy ctor // Copy a into vector
// Second push_back() (capacity now grows to 2)
Copy ctor // Copy rocks[0] to new storage
Copy ctor // Copy b into vector
Dtor // Destruct rocks[0] in old storage
// Third push_back() (capacity now grows to 4)
Copy ctor // Copy rocks[0] to new storage
Copy ctor // Copy rocks[1] to new storage
Copy ctor // Copy c into vector
Dtor // Destruct rocks[0] in old storage
Dtor // Destruct rocks[1] in old storage
// End of main
Dtor // Destruct rocks[0]
Dtor // Destruct rocks[1]
Dtor // Destruct rocks[2]
Dtor // Destruct c
Dtor // Destruct b
Dtor // Destruct a
答案 2 :(得分:1)
很容易修改代码以打印更多信息:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Rock{
int sz;
public:
Rock():sz(0){cout<< "Default ctor"<<endl;}
Rock(int x):sz(x){cout<< "int ctor " << x <<endl;}
~Rock(){cout<< "Dtor " << sz <<endl;}
Rock(const Rock& r){ cout << "Copy ctor from " << r.sz << endl; sz = r.sz;}
Rock& operator=(const Rock& r) {cout << "Copy ctor " << sz << " from " << r.sz << endl; sz = r.sz;}
};
int main()
{
vector<Rock> rocks;
Rock a(1), b(2), c(3);
rocks.push_back(a);
rocks.push_back(b);
rocks.push_back(c);
return 0;
}
打印(带说明):
int ctor 1
int ctor 2
int ctor 3
Copy ctor from 1 // copies a into the vector
// push_back(a) returns (capacity == 1)
Copy ctor from 1 // vector reallocates to a greater storage
Copy ctor from 2 // copies b into the vector
Dtor 1 // destroy the old elements
// push_back(b) returns (capacity == 2)
Copy ctor from 1 // vector reallocates to a greater storage
Copy ctor from 2
Copy ctor from 3 // copy c into the vector
Dtor 1 // destroy the old elements
Dtor 2
// push_back(c) returns (capacity == 4)
Dtor 3 // destroy the local a, b, c
Dtor 2
Dtor 1
Dtor 1 // destroy the vector and its elements
Dtor 2
Dtor 3