c++ - 为什么vector的方法resize会创建一个额外的对象?
问题描述
根据我的理解,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 !
所以我的问题是:为什么要创建一个新对象然后销毁它?为什么创建的第一个对象的地址离其他对象很远?
解决方案
您的编译器对您给出的代码做了一些奇怪的事情,我只能假设这是因为您使用的是 C++11 之前的版本。在C++11 之前的方法cppreferenceresize
中,如果未指定,则将默认构造对象作为第二个参数。这将导致对构造函数的调用。
如果当前大小小于 count,则附加元素并使用 value 的副本进行初始化。
这意味着默认构造的对象将被复制到向量中分配的两个新点中;这就是您在 mingw 中看到的
在 C++11 及更高版本中,它应该只调用两次构造函数和两次析构函数,不涉及副本。调用时t.resize(2)
,会将两个“默认插入”对象添加到容器中,这些对象将调用构造函数。当向量超出范围并被销毁时,将调用析构函数。
如果您改为执行以下操作:
t.resize(2);
t.resize(5);
现在,当且仅当重新分配内部数组时,您将在第二次调整大小时获得一些副本或移动。前两个元素将从旧数组复制或移动到新数组。最后 3 个元素将默认插入到新数组中。
至于对象内存地址的巨大差异,这实际上就是计算机中的工作方式。初始数组分配在一块动态内存中;然后调整大小会获得一个新的内存位置,它可能就在旧位置的旁边,或者可能完全在其他地方。
这是C++17 和 C++11的演示。
推荐阅读
- amazon-web-services - Birst 代理连接错误:“错误:无法找到或加载主类 com.birst.agent.AgentInitializer”
- next.js - 在 NextJS 上的服务器端渲染中为动态页面预构建组件
- css - CSS 文件和检查器不匹配
- python - 查找两列的最大值并在第三列中填充值
- wordpress - 使用 TM 全球额外选项后,价格未显示在购物车和结帐页面中
- mongodb - 考虑在你的配置中定义一个 'org.springframework.data.mongodb.core.convert.MappingMongoConverter' 类型的 bean
- css - 字体 ::selection 高度不随 line-height 变化
- angular - 为什么模块构造函数中可以有服务未定义?
- reactjs - 在我的 React JS 应用程序中,我的 onClick 函数是在加载时发生的,而不是在我单击按钮时发生的。尝试对 JSON 数组进行排序
- squirrel - 我如何确保 quirrel 中存在路径