在对象初始化之前访问 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 对象成员的主要内容,如果未能解决你的问题,请参考以下文章

在 C++ 中初始化对象之前声明一个对象

C++ 「静态数据成员」和「静态成员函数」的简单认识

多线程设计,保护C++中的全局成员

构造函数中的引用向量:未初始化的引用

push_back 对象引用

Heremei C++