【问题标题】:Accessing C++ std::vector object members before object initialization在对象初始化之前访问 C++ std::vector 对象成员
【发布时间】: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值的原因

标签: c++ vector


【解决方案1】:

因为operator[] 不进行任何边界检查(并且在编译优化的二进制文件时仅转换为一些指针算法)。这样std::vector 就可以像普通的 C 数组一样有效地使用。

您读取的0 恰好位于内存中,其中向量在堆上保留了空间。请注意,操作系统会使用0 作为安全措施初始化程序的内存(因此您无法查看旧数据)。如果您的应用程序运行时间更长并且页面被回收,您还可以观察其他垃圾值。

你可以试试at(),它会检查边界。

【讨论】:

  • 好吧,我知道我可以访问内存并在其中写任何废话。但我不明白为什么我可以访问未初始化对象的成员轮胎。我编辑了我的示例并添加了一个构造函数以使其更加清晰。
  • 请注意,访问这个保留的内存有未定义的行为。不允许使用它,即使您的解释很可能在实践中产生。
  • @muella91 对结构/类成员的访问最终还是指针算术。编译器希望你知道你在做什么;它产生愚蠢但有效的机器代码。您的任务是不要编写导致未定义行为的代码。
【解决方案2】:

访问std::vector 超出其大小(不是其容量)的元素具有undefined behavior

未定义的行为意味着不能保证一般情况下会发生任何特定的事情。究竟会发生什么将取决于编译器和标准库的特定实现。

@ypnos 提到了一种可能的行为,但(任何)其他行为也是 C++ 标准允许的,并且可能取决于标准库如何实现 std::vector 以及编译器如何优化。

【讨论】:

    猜你喜欢
    • 2017-01-17
    • 2016-05-03
    • 1970-01-01
    • 1970-01-01
    • 2010-10-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多