在将对象插入向量时了解构造,复制和销毁

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在将对象插入向量时了解构造,复制和销毁相关的知识,希望对你有一定的参考价值。

我试图了解STL如何处理对象的插入。我知道STL从临时调用构造函数或复制构造。

这是我试图理解的代码:

#include <iostream>
#include <string>
#include <vector>
using namespace std;

class A
{
      public:
      int ObjId;;
      A(int id) : ObjId(id)
      {
            cout << "Constructing object with id: " << ObjId << endl;
      }

      A(const A& objToCpy)
      {
            ObjId = objToCpy.ObjId;
            cout << "Copying object with id: " << ObjId << endl;
       }

      ~A()
      {
            cout << "Destructing object with id: " << ObjId << endl;
      }
};


int main()
{
      std::vector<A> vecOfA;

      vecOfA.push_back(A(1));

      cout << "....................." << endl << endl;

      vecOfA.push_back(A(2));

      return 0;
}

这给出了以下输出:

构造id为1的对象

复制id为1的对象

ID为1的解构对象

................

构造id为2的对象

复制id为2的对象

复制id为1的对象

ID为1的解构对象

ID为2的解构对象

................

ID为1的解构对象

ID为2的解构对象

我能理解第一次插入。创建ID = 1的临时对象,然后复制构造并插入到向量中。然后这个临时性被破坏了。

但是,我不明白为什么复制的对象有ID = 0,而不是1。

至于第二部分,我不知道发生了什么以及为什么它与第一次插入不同,唯一的例外是ID不同。为什么要复制2个对象,并且ID为0,而不是2。

任何人都可以帮我理解这种行为吗?

答案

在第一种情况下,你保持ObjId未初始化,这意味着你很幸运,插入了0,但基本上也可以看到任何值。

通过输入A(const A& other) {...},您可以定义自己的复制构造函数,这意味着您将显示每个字段的复制方式,因此您会错过构造函数中的ObjId = other.ObjId语句。

第二种情况发生是因为您的向量正在调整大小,因此它必须将所有元素从旧存储复制到新的,更大的存储,这也将适合新元素。

另一答案

但是,我不明白为什么复制的对象有ID = 0,而不是1。

您的复制构造函数将ObjId保留为未初始化,因此在访问该值时,程序的行为是不确定的。


至于第二部分,我不知道发生了什么以及为什么它与第一次插入不同,唯一的例外是ID不同。为什么要复制2个对象

这是因为动态数组数据结构 - 这是std::vector的作用 - 是如何工作的。数组无法调整大小。一旦向量的内部数组太小,就会创建一个更大的数组,将旧元素复制(或移动)到新数组,并销毁旧数组。


这意味着矢量通常初始化为1的容量?

一个实验并没有告诉我们通常会做什么。似乎在第一次推送之后,在这种情况下,系统上的容量确实是一个。无法保证在其他情况下(例如std::vector的其他实现)。

以上是关于在将对象插入向量时了解构造,复制和销毁的主要内容,如果未能解决你的问题,请参考以下文章

对复制构造函数已被删除的对象向量进行迭代 (C2280)

C++ - 未分配被释放的指针

现有对象的向量

Android:使用支持片段管理器时复制片段

Initializer-list-构造一个不可复制(但可移动)对象的向量

为啥在按值返回时总是调用复制构造函数