为何所有this指针值相同?如何创建独立myclass对象?
代码片段
#include <iostream> #include <vector> class myclass { public: myclass() { std::cout << this << std::endl; } }; int main() { std::vector<myclass> v; for(uint32_t i = 0; i < 10; i++) v.push_back(myclass()); return 0; }
编译与输出
使用命令 g++ main.cpp 编译后,执行二进制文件输出如下:
0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab 0x7ffebb8f8cab
用户疑问
为何所有this指针的值都完全相同?我创建了10个同一类的不同对象,应该对应10个不同的this指针才对,不是吗?
我理解当前代码可能是复用了同一对象的引用来填充vectorv,但我需要的是10个独立的myclass对象。该如何实现?由于这段代码属于一个大型项目,项目中new和delete存在问题,因此不能使用这两个API。请问我哪里出错了?该如何修复?
原因分析
你看到的重复this地址是临时对象的地址,而非vector中存储的对象地址:
push_back(myclass())会先在栈上创建一个临时的myclass对象,此时调用构造函数输出临时对象的this;- 随后vector会将这个临时对象拷贝到自己的存储区中,但你没有显式定义拷贝构造函数,编译器生成的默认拷贝构造不会打印
this; - 临时对象在拷贝完成后立即被销毁,下一次循环会在栈的同一个位置重新创建新的临时对象,因此每次输出的
this地址完全相同。
实际上vector中已经存储了10个独立的myclass对象,只是它们的构造(拷贝构造)没有被打印出来。你可以通过遍历vector打印每个元素的地址验证:
for (auto& obj : v) { std::cout << &obj << std::endl; }
执行后会看到10个不同的地址。
修复方案(无需new/delete)
要让构造函数输出的this对应vector中独立对象的地址,有几种方法:
1. 提前预留空间+emplace_back直接构造
先调用reserve为vector预分配足够内存,避免扩容;再用emplace_back直接在vector的内存空间中构造对象,完全避免临时对象:
int main() { std::vector<myclass> v; v.reserve(10); // 预分配10个对象的内存 for(uint32_t i = 0; i < 10; i++) v.emplace_back(); // 直接在vector内存中构造对象 return 0; }
此时输出的10个this地址都是vector存储区的不同地址,对应10个独立对象。
2. 直接resize创建对象
如果不需要循环中做额外操作,直接用resize一次性创建10个对象:
int main() { std::vector<myclass> v; v.resize(10); // 直接构造10个对象到vector中 return 0; }
这种方式会直接在vector的内存中构造10个独立对象,输出的this地址各不相同。
3. 仅用emplace_back(无reserve)
即使不提前预留空间,emplace_back也会直接在vector当前的内存中构造对象,但如果vector扩容(内存不足时),已有的对象会被拷贝到新的内存区域。不过构造新对象时的this地址仍然是不同的,只是扩容过程中会触发拷贝构造(若未定义移动构造)。
内容的提问来源于stack exchange,提问作者Setu

