请查看我的代码。我有一个基类“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
}
使用引用作为类成员通常是糟糕设计的标志。在你的情况下,情况更糟,因为你创建了自引用对象。在这种情况下,你不能依赖规则0,而应该依赖规则3或规则5。
向量上的每个
emplace_back
都会重新分配向量,并将值从旧分配移动到新分配。因为您遵循规则 0,所以复制/移动由自动生成的 default
代码处理;因此,system
引用被按位复制,并且由于原始自引用对象被破坏,最终会得到一个悬空引用,它指向任何地方(随机内存位置)。这是UB的多功能保护壳。您可以通过 vector::reserve
方法预先分配向量来推迟灾难,但这只会隐藏实际问题并为灾难赢得时间。
最终的解决方案是修改您的设计,以防止在任何情况下出现悬空参考问题。您需要为您的类正确定义复制或移动构造函数。这就是为什么我建议您遵循第 1 段中的建议。