我正在为我正在编写的库编写一些测试代码,其中涉及一些类的向量,而在这些类内部有更多的向量。很标准的东西。
以下是简化版本:
struct TestContainerEntry
{
double data = 5;
TestContainerEntry() { std::cout << __FUNCTION__ << " " << (void *)this << "\n"; }
~TestContainerEntry() { std::cout << __FUNCTION__ << " " << (void *)this << "\n"; }
};
struct TestContainer
{
vector<TestContainerEntry> testContainerEntries;
TestContainer()
{
testContainerEntries.reserve(128);
std::cout << __FUNCTION__ << " " << (void *)this << "\n";
}
~TestContainer() { std::cout << __FUNCTION__ << " " << (void *)this << "\n"; }
TestContainerEntry& addTestContainerEntry()
{
return testContainerEntries.emplace_back();
}
};
struct TestParent
{
vector<TestContainer> testContainer;
TestParent()
{
testContainer.reserve(128);
std::cout << __FUNCTION__ << " " << (void *)this << "\n";
}
TestContainer& addTestContainer()
{
return testContainer.emplace_back();
}
};
现在,我认为对emplace_back()使用新的C ++ 17重载,将元素添加到向量中并返回修改参考是一个很好的模式。 这似乎可以正常工作,但前提是您必须非常小心地使用返回的引用。
如果您重复使用相同的引用,将无法正常工作:在这种情况下,析构函数将在子向量的元素上运行并释放数据。
我不明白为什么会这样。对象是在向量内部构造的,但似乎引用的生命周期正在影响向量中元素的生命周期。 现在我知道引用可以延长临时对象的寿命,但是在这种情况下,我不认为这是临时的,因为它是存储在向量中的对象。
我知道我可以更改编码方式来避免此问题,但是我有兴趣找出问题的出处以及是否由于我的错误而引起。
这是工作案例及其打印内容:
TestParent t;
TestContainer& tc1 = t.addTestContainer();
tc1.addTestContainerEntry();
tc1.addTestContainerEntry();
TestContainer& tc2 = t.addTestContainer();
tc2.addTestContainerEntry();
tc2.addTestContainerEntry();
TestContainer& tc3 = t.addTestContainer();
tc3.addTestContainerEntry();
tc3.addTestContainerEntry();
输出
TestParent::TestParent 000000338131F848
TestContainer::TestContainer 0000013C60000400
TestContainerEntry::TestContainerEntry 0000013C5FFF9FD0
TestContainerEntry::TestContainerEntry 0000013C5FFF9FD8
TestContainer::TestContainer 0000013C60000420
TestContainerEntry::TestContainerEntry 0000013C60001450
TestContainerEntry::TestContainerEntry 0000013C60001458
TestContainer::TestContainer 0000013C60000440
TestContainerEntry::TestContainerEntry 0000013C60001890
TestContainerEntry::TestContainerEntry 0000013C60001898
这是失败的情况:
TestParent t;
TestContainer& tc = t.addTestContainer();
tc.addTestContainerEntry();
tc.addTestContainerEntry();
tc = t.addTestContainer();
tc.addTestContainerEntry();
tc.addTestContainerEntry();
tc = t.addTestContainer();
tc.addTestContainerEntry();
tc.addTestContainerEntry();
输出
TestParent::TestParent 0000003C1632F958
TestContainer::TestContainer 000001915536F0C0
TestContainerEntry::TestContainerEntry 0000019155370120
TestContainerEntry::TestContainerEntry 0000019155370128
TestContainer::TestContainer 000001915536F0E0
TestContainerEntry::~TestContainerEntry 0000019155370120
TestContainerEntry::~TestContainerEntry 0000019155370128
TestContainerEntry::TestContainerEntry 0000019155370120
TestContainerEntry::TestContainerEntry 0000019155370128
TestContainer::TestContainer 000001915536F100
TestContainerEntry::~TestContainerEntry 0000019155370120
TestContainerEntry::~TestContainerEntry 0000019155370128
TestContainerEntry::TestContainerEntry 0000019155370120
TestContainerEntry::TestContainerEntry 0000019155370128
有人可以解释这里发生了什么吗?
编辑: 根据评论,我可以这样编写测试代码:我是问题,还可以避免为引用提供唯一的名称。
TestParent t;
{
TestContainer& tc = t.addTestContainer();
tc.addTestContainerEntry();
tc.addTestContainerEntry();
}
{
TestContainer& tc = t.addTestContainer();
tc.addTestContainerEntry();
tc.addTestContainerEntry();
}
...