了解将对象插入向矢量时的构造、复制和销毁

Understanding the construction, copy and destruction when inserting objects to a vector

提问人:madu 提问时间:9/11/2018 最后编辑:madu 更新时间:9/11/2018 访问量:49

问:

我正在尝试了解 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。

谁能帮我理解这种行为?

C++ Vector STL 复制构造函数

评论

3赞 463035818_is_not_an_ai 9/11/2018
“我不明白为什么复制的对象有 ID=0,而不是 1。” 您的复制构造函数不会复制任何内容...
1赞 SJHowe 9/11/2018
我更喜欢使用复制构造函数成员初始化。所以A(const A& objToCpy) : Objid(objToCpy.Objid) { cout << "Copying object with id: " << ObjId << endl; }

答:

1赞 eerorika 9/11/2018 #1

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

复制构造函数保持未初始化状态,因此在访问该值时未定义程序的行为。ObjId


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

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


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

一个实验并不能说明向量通常做什么。看来,在第一次推送之后,在这种情况下,您的系统上的容量确实是一个。不能保证在其他情况下(例如 的其他实现)中它会是一个。std::vector

评论

0赞 madu 9/11/2018
谢谢。我的错误。我更改了复制构造函数(编辑了问题),但我仍然看到第二次插入的多个对象。
0赞 madu 9/11/2018
谢谢。你是对的。当我保留()时,它起作用了。
1赞 Krzysztof Lewko 9/11/2018 #2

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

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

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

评论

0赞 madu 9/11/2018
你是对的!当我做 reserve(10) 时,得到了我预期的行为。谢谢。这意味着向量通常初始化为容量为 1?
1赞 Krzysztof Lewko 9/11/2018
是的,这是这个特定 vector 实现的初始值。但是,我不确定最初是否为 0,并且每当您添加一个元素时,它都会分配任何额外的内存。但这在这里并不重要。
0赞 463035818_is_not_an_ai 9/11/2018
未初始化会导致未定义的行为,没有运气ObjId
0赞 463035818_is_not_an_ai 9/11/2018
实际上,给你带来你所期望的结果是最糟糕的,因为你不会发现它,直到为时已晚