c++对基类的引用的未定义行为

fv2wmkja  于 11个月前  发布在  其他
关注(0)|答案(1)|浏览(76)

请看我的代码。我有一个基类“System”和一个派生类“AdvancedSystem”。当访问基类引用时,输出是未定义的和随机的,我不知道为什么。如果派生类给了我预期的输出。有什么想法吗?

#include <iostream>
#include <vector>

class System {
public:
    System() :
        someValue(12345)
    {}
 
    int someValue;
};

class AdvancedSystem : public System {
public:
    AdvancedSystem()
    {}
};

class Strategies {
public:
    Strategies(System& system) :
        system(system)
    {}

    System& system;
};

class Test {
public:
    Test() :
        system(),
        strategies(system)
    {}

    AdvancedSystem system;
    Strategies strategies;
};

class Tests {
public:
    void createTests() {
        for (int i = 0; i < 18; ++i) {
            values.emplace_back();
        }
    }

    std::vector<Test> values;
};

int main() {
    Tests tests;
    tests.createTests();
    std::cout << tests.values[0].system.someValue << "\n"; // outputs expected value of 12345
    std::cout << tests.values[0].strategies.system.someValue << "\n"; // outputs random number
}

字符串

dfty9e19

dfty9e191#

使用引用作为类成员通常是糟糕设计的标志。在你的情况下,这更糟糕,因为你创建了自引用对象。在这种情况下,你不能依赖rule 0,而是rule 3rule 5
在你的vector上的每个emplace_back,vector被重新分配,值从旧的分配移动到新的分配。因为你遵循规则0,复制/移动是由自动生成的default代码处理的;因此system引用被逐位复制并且由于原始自引用对象被析构,你最终会得到一个dangling reference,它无处可去(随机内存位置)。这是UB的一个通用情况。你可以通过vector::reserve方法预分配向量来推迟灾难,但这只是隐藏了实际问题,为灾难赢得了时间。
最终的解决方案是修改你的设计,以防止在任何情况下出现悬空引用问题。你需要为你的类正确定义复制或移动构造函数。这就是为什么我建议你遵循第1段中的建议。

相关问题