为什么 vector 的方法调整大小会创建一个额外的对象?



根据我的理解,模板类resize方法vector<class>使用不带参数的构造函数创建一个新对象,然后使用复制构造函数克隆以前的对象。事实上,这段代码证明了这一点:

#include <iostream>
#include <vector>
using namespace std;
class A{
public:
A(){
cout << "Appel constructeur !" << endl;
cout << this << endl;
}
A(const A &a){
cout << "Appel constructeur de recopie" << endl;
cout << this << endl;
}
~A(){
cout << "Appel destructeur !" << endl;
}
};
int main() {
vector<A> t;
t.resize(2);
cout << t.size() << endl;
cout << &t[0] << endl;
cout << &t[1] << endl;
}

输出带有mingw32-g++.exe

Appel constructeur !
0x69fedf
Appel constructeur de recopie
0x905690
Appel constructeur de recopie
0x905691
Appel destructeur !
2
0x905690
0x905691
Appel destructeur !
Appel destructeur !

带有g++的输出(它调用构造函数两次(

Appel constructeur !
0x55c91bff3e70
Appel constructeur !
0x55c91bff3e71
2
0x55c91bff3e70
0x55c91bff3e71
Appel destructeur !
Appel destructeur !

所以我的问题是:为什么要创建一个新对象然后销毁它?为什么创建的第一个对象的地址与其他对象相去甚远?

vector 使用

不带参数的构造函数创建一个新对象,然后使用复制构造函数克隆前一个对象。事实上,这段代码证明了这一点:

代码输出并不能证明任何事情,它只显示一个特定的编译器在一种特定情况下做了什么。

在 C++11 之前,标准指定新元素的创建就像通过从值初始化的临时insert复制构造一样。 因此,地址不同,因为向量中的对象位于动态存储中,而临时对象位于临时(或自动(存储中。

从 C++11 开始,它必须使用默认插入创建新对象,这归结为默认分配器的值初始化。

您的结果很可能通过使用旧的编译器(或在较新的编译器上不使用 C++11 模式(来解释。

您的编译器正在为您给出的代码做一些奇怪的事情,我只能假设这是因为您使用的是 pre C++11。从 cpp首选项中,C++11 之前的resize方法采用默认构造对象作为第二个参数(如果未指定(。这将导致对构造函数的调用。

如果当前大小小于计数,则会附加其他元素并使用值的副本进行初始化。

这意味着默认的构造对象将被复制到向量中分配的两个新点中;这就是你在mingw中看到的

。在 C++11 及更高版本中,它应该只调用构造两次,析构函数调用两次,不涉及副本。调用t.resize(2)时,会将两个"默认插入"对象添加到容器中,这些对象将调用构造函数。当向量超出范围并销毁时,将调用析构函数。

如果改为执行以下操作:

t.resize(2);
t.resize(5);

现在,您将在第二次调整大小时获得一些副本或移动,当且仅当重新分配内部数组时。前两个元素将被复制或从旧数组移动到新数组。最后 3 个元素将被默认插入到新数组中。

至于对象内存地址的巨大差异,这实际上只是计算机中的工作方式。初始数组被分配到动态内存的一个位置;然后,调整大小将获得一个新的内存位置,该位置可能紧挨着旧位置,也可能完全位于其他位置。

这是 C++17 和 C++11 的演示。

最新更新