在对象初始化之前访问 C++ std::vector 对象成员
Posted
技术标签:
【中文标题】在对象初始化之前访问 C++ std::vector 对象成员【英文标题】:Accessing C++ std::vector object members before object initialization 【发布时间】:2020-02-18 08:30:47 【问题描述】:我刚刚意识到我可以访问我的空对象向量列表的对象成员。 我认为 vector.reserve(nmb) 只是保留所需的内存(一种 nmb*sizeof(object))。
#include <iostream>
#include <vector>
class Car
public: int tires = 4;
Car(void)
std::cout << "Constructor of Car" << std::endl;
;
int main()
std::vector<Car> carList;
carList.reserve(20);
std::cout << "Car tires: " << carList[0].tires << std::endl;
std::cout << "Now comes the emplace_back:" << std::endl;
carList.emplace_back();
std::cout << "Car tires: " << carList[0].tires << std::endl;
//Car carArray[20];
//std::cout << "Car tires: " << carArray[0].tires << std::endl;
return 0;
给我:
Car tires: 0
Now comes the emplace_back:
Constructor of Car
Car tires: 4
...Program finished with exit code 0
为什么我可以访问尚未初始化的对象的成员? 谢谢。
【问题讨论】:
因为这些对象的内存由carList.reserve(20);
保留在向量中,但是这个内存没有初始化,所以这就是你有thrash值的原因
【参考方案1】:
因为operator[]
不进行任何边界检查(并且在编译优化的二进制文件时仅转换为一些指针算法)。这样std::vector
就可以像普通的 C 数组一样有效地使用。
您读取的0
恰好位于内存中,其中向量在堆上保留了空间。请注意,操作系统会使用0
作为安全措施初始化程序的内存(因此您无法查看旧数据)。如果您的应用程序运行时间更长并且页面被回收,您还可以观察其他垃圾值。
你可以试试at()
,它会检查边界。
【讨论】:
好吧,我知道我可以访问内存并在其中写任何废话。但我不明白为什么我可以访问未初始化对象的成员轮胎。我编辑了我的示例并添加了一个构造函数以使其更加清晰。 请注意,访问这个保留的内存有未定义的行为。不允许使用它,即使您的解释很可能在实践中产生。 @muella91 对结构/类成员的访问最终还是指针算术。编译器希望你知道你在做什么;它产生愚蠢但有效的机器代码。您的任务是不要编写导致未定义行为的代码。【参考方案2】:访问std::vector
超出其大小(不是其容量)的元素具有undefined behavior。
未定义的行为意味着不能保证一般情况下会发生任何特定的事情。究竟会发生什么将取决于编译器和标准库的特定实现。
@ypnos 提到了一种可能的行为,但(任何)其他行为也是 C++ 标准允许的,并且可能取决于标准库如何实现 std::vector
以及编译器如何优化。
【讨论】:
以上是关于在对象初始化之前访问 C++ std::vector 对象成员的主要内容,如果未能解决你的问题,请参考以下文章