对向量进行复制构造的实验
experiment with copy construction for a vector
在尝试通过"pass-by-value"进行复制构建和随后的销毁时,我尝试了以下代码:
#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
让我们将输出与相应的代码行相关联。
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
的副本,将其存储在旧内存块中的a
的副本复制到新内存块,然后复制b
,然后在释放(现在不再需要)原始内存块之前销毁a
的原始副本。
rocks.push_back(c);
Copy ctor
Copy ctor
Copy ctor
Dtor
Dtor
根据上面的解释,你现在应该能够猜到这里发生了什么。
然而,请注意,如果将另一个元素推回到向量中,很可能再次只得到一个复制构造函数,而没有析构函数调用。这是因为向量的典型策略是在每一步中将分配的内存增加一倍,因此当推回c
时,它很可能会为4个对象分配空间。实际上,std::vector
需要使用指数策略(但不需要使用因子2,而且有人认为黄金平均数是一个更好的因子)。
}
Dtor
Dtor
Dtor
Dtor
Dtor
Dtor
这里,三个对象c
、b
、a
,然后向量中的三个对象被破坏。
很容易修改代码以打印更多信息:
#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
每当std::vector
必须增加其容量时(因为您正在推送更多元素),它需要分配新的存储,将所有现有元素从旧存储复制到新存储,然后删除旧元素。因此,您将获得对复制构造函数和析构函数的"额外"调用。
如果在每次对push_back
的调用之间放入一个cout
语句,这将有助于澄清哪些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
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 在C++程序中输入的文本文件将不起作用,除非文本被复制和粘贴
- 使用strcpy将char数组的元素复制到另一个数组
- 是否可以初始化不可复制类型的成员变量(或基类)
- 为什么在C++中使用私有复制构造函数与删除复制构造函数
- C++ Windows 驱动程序MSB3030无法复制该文件,因为它找不到
- 复制列表初始化的隐式转换的等级是多少
- 当从函数参数中的临时值调用复制构造函数时
- 有可能在Armadillo中复制MATLAB circshift方法吗
- 复制几乎为空的数组的最快方法
- 以下示例中如何避免代码复制?C++/库达
- 如果有一个模板构造函数只有一个泛型参数,为什么我必须有一个复制构造函数
- 为什么需要复制构造函数,在哪些情况下它们非常有用
- 不能将复制初始化与隐式转换的多个步骤一起使用
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 为什么复制而不是移动数据元素?
- 文件系统:复制功能的速度秘诀是什么
- 使用仅使用一次的变量调用的复制构造函数.这可能是通过调用move构造函数进行编译器优化的情况吗
- 为什么类中的ostringstream类型的成员会导致";调用隐含删除复制构造函数";错误
- 对向量进行复制构造的实验