C ++ 17 emplace_back参考调用析构函数

时间:2019-02-28 12:49:23

标签: c++ visual-c++ reference c++17 emplace

我正在为我正在编写的库编写一些测试代码,其中涉及一些类的向量,而在这些类内部有更多的向量。很标准的东西。

以下是简化版本:

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();
}

...

0 个答案:

没有答案