首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >C++:将自动分配的对象添加到std::vector

C++:将自动分配的对象添加到std::vector
EN

Stack Overflow用户
提问于 2011-06-01 05:40:14
回答 4查看 2.2K关注 0票数 4

我写了以下代码:

代码语言:javascript
复制
#include <iostream>
#include <vector>
using namespace std;

class AClass
{
    public:
        int data;

        AClass() 
        { data = -333; cout << "+ Creating default " << data << endl; }

        AClass(const AClass &copy) 
        { 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;
}

程序的输出是:

代码语言:javascript
复制
+ 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

然后,我将类更改为:

代码语言:javascript
复制
class AClass
{
    public:
        int data;

        AClass(int d) 
        { data = d; cout << "+ Creating " << data << endl; }

        ~AClass() 
        { cout << "- Deleting " << data << endl; }
};

然后输出变成:

代码语言:javascript
复制
+ 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似乎正在复制现有对象,但似乎正在发生许多不必要的分配/删除。为什么会这样呢?另外,为什么在我没有提供复制构造函数的情况下,第二个版本可以工作呢?

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2011-06-01 05:45:51

似乎向量在添加新对象时正在复制现有对象

当您添加元素时,例如使用v.push_back(AClass(i));,所做的就是创建一个临时的AClass对象并将其传递给push_back。然后,push_back必须将该对象复制到容器中。

您看到复制的另一个原因是std::vector将其元素连续地存储在一个数组中。如果底层数组中没有剩余空间,并且您尝试在末尾添加另一个元素,则std::vector必须创建一个新数组,将旧数组中的元素复制到新数组中,然后在末尾插入新元素。如果不希望发生这种情况,可以在开始插入元素之前调用std::vector::reservestd::vector中保留足够的空间,或者可以使用不同的序列容器,如std::deque,它不会连续存储其元素。

似乎发生了很多不必要的分配/删除操作

在C++程序中,对象经常被创建和销毁。请注意,在您的程序中,复制AClass的成本非常低:它的大小可能是4或8个字节,仅足以容纳它的int数据成员。

如果你有一个复制成本很高的类型(例如,也许你有一个包含数千个节点的大型树数据结构),那么是的,复制可能太昂贵了。在这种情况下,您可以将指向动态分配的对象的智能指针存储在std::vector中(例如,std::vector<shared_ptr<AClass> > )。如果您的编译器支持右值引用,并且具有支持移动的标准库实现,则可以通过实现移动构造函数和移动赋值运算符并使用emplace_back而不是push_back来使复制成本较高的类型可移动。

为什么在我没有提供复制构造函数的情况下第二个版本可以工作?

如果不声明复制构造函数,编译器将为您提供默认的复制构造函数。

票数 5
EN

Stack Overflow用户

发布于 2011-06-01 05:45:24

Vector使用一个规则的T数组作为它的存储--当您创建一个这样的存储时,它必须以某种方式初始化空间,唯一的选择是一个默认构造函数。稍后,当您设置索引的值时,它会将其复制到该空间中。

在第二个版本中,即使您没有提供复制构造函数,也会自动为您生成一个。如果你声明了一个私有的,然后又没有实现它,你将会看到一个编译器错误(因为你已经抑制了默认的生成)

票数 5
EN

Stack Overflow用户

发布于 2011-06-01 05:44:26

您的对象被复制,因为vector正在扩展其内部存储。如果您想要避免副本,请预先调用vector::reserve来预分配内存。如果您不提供自己的复制ctor,编译器将为您生成一个复制ctor(复制所有成员的ctor)。

票数 3
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/6193889

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档