我写了以下代码:
#include <iostream>
#include <vector>
using namespace std;
class AClass
{
public:
int data;
AClass()
{ data = -333; cout << "+ Creating default " << data << endl; }
AClass(const AClass ©)
{ data = copy.data; cout << "+ Creating copy of " << data << endl; }
AClass(int d)
{ data = d; cout << "+ Creating " << data << endl; }
~AClass()
{ cout << "- Deleting " << data << endl; }
AClass& operator = (const AClass &a)
{ data = a.data; cout << "= Calling operator=" << endl; }
};
int main(void)
{
vector<AClass> v;
for (int i = 3; i--; )
v.push_back(AClass(i));
vector<AClass>::iterator it = v.begin();
while (it != v.end())
cout << it->data << endl, it++;
return 0;
}程序的输出是:
+ Creating 2
+ Creating copy of 2
- Deleting 2
+ Creating 1
+ Creating copy of 1
+ Creating copy of 2
- Deleting 2
- Deleting 1
+ Creating 0
+ Creating copy of 0
+ Creating copy of 2
+ Creating copy of 1
- Deleting 2
- Deleting 1
- Deleting 0
2
1
0
- Deleting 2
- Deleting 1
- Deleting 0然后,我将类更改为:
class AClass
{
public:
int data;
AClass(int d)
{ data = d; cout << "+ Creating " << data << endl; }
~AClass()
{ cout << "- Deleting " << data << endl; }
};然后输出变成:
+ Creating 2
- Deleting 2
+ Creating 1
- Deleting 2
- Deleting 1
+ Creating 0
- Deleting 2
- Deleting 1
- Deleting 0
2
1
0
- Deleting 2
- Deleting 1
- Deleting 0在添加新对象时,vector似乎正在复制现有对象,但似乎正在发生许多不必要的分配/删除。为什么会这样呢?另外,为什么在我没有提供复制构造函数的情况下,第二个版本可以工作呢?
发布于 2011-06-01 05:45:51
似乎向量在添加新对象时正在复制现有对象
当您添加元素时,例如使用v.push_back(AClass(i));,所做的就是创建一个临时的AClass对象并将其传递给push_back。然后,push_back必须将该对象复制到容器中。
您看到复制的另一个原因是std::vector将其元素连续地存储在一个数组中。如果底层数组中没有剩余空间,并且您尝试在末尾添加另一个元素,则std::vector必须创建一个新数组,将旧数组中的元素复制到新数组中,然后在末尾插入新元素。如果不希望发生这种情况,可以在开始插入元素之前调用std::vector::reserve在std::vector中保留足够的空间,或者可以使用不同的序列容器,如std::deque,它不会连续存储其元素。
似乎发生了很多不必要的分配/删除操作
在C++程序中,对象经常被创建和销毁。请注意,在您的程序中,复制AClass的成本非常低:它的大小可能是4或8个字节,仅足以容纳它的int数据成员。
如果你有一个复制成本很高的类型(例如,也许你有一个包含数千个节点的大型树数据结构),那么是的,复制可能太昂贵了。在这种情况下,您可以将指向动态分配的对象的智能指针存储在std::vector中(例如,std::vector<shared_ptr<AClass> > )。如果您的编译器支持右值引用,并且具有支持移动的标准库实现,则可以通过实现移动构造函数和移动赋值运算符并使用emplace_back而不是push_back来使复制成本较高的类型可移动。
为什么在我没有提供复制构造函数的情况下第二个版本可以工作?
如果不声明复制构造函数,编译器将为您提供默认的复制构造函数。
发布于 2011-06-01 05:45:24
Vector使用一个规则的T数组作为它的存储--当您创建一个这样的存储时,它必须以某种方式初始化空间,唯一的选择是一个默认构造函数。稍后,当您设置索引的值时,它会将其复制到该空间中。
在第二个版本中,即使您没有提供复制构造函数,也会自动为您生成一个。如果你声明了一个私有的,然后又没有实现它,你将会看到一个编译器错误(因为你已经抑制了默认的生成)
发布于 2011-06-01 05:44:26
您的对象被复制,因为vector正在扩展其内部存储。如果您想要避免副本,请预先调用vector::reserve来预分配内存。如果您不提供自己的复制ctor,编译器将为您生成一个复制ctor(复制所有成员的ctor)。
https://stackoverflow.com/questions/6193889
复制相似问题