在调用emplace_back期间修改std :: deque是否合法?

时间:2013-06-06 06:36:23

标签: c++ c++11 language-lawyer deque libc++

我正在使用emplace_backstd::deque添加项目。在构造过程中,新项目可能会将其他项目添加到正在构建的std::deque中。这导致非常有趣的行为。请考虑以下代码段:

#include <iostream>
#include <deque>
#include <string>

struct foo
{
    std::string m_marker;

    foo(std::deque<foo>& into, const std::string& marker, bool createInner = true)
    : m_marker(marker)
    {
        if (createInner)
        {
            std::cout << "Marker is " << m_marker << std::endl;
            into.emplace_back(into, "my other marker", false);
            std::cout << "Marker is now " << m_marker << std::endl;
        }
    }
};

int main()
{
    std::deque<foo> foos;
    foos.emplace_back(foos, "my initial marker");

    std::cout << "There are " << foos.size() << " items in the deque:" << std::endl;
    for (foo& f : foos)
    {
        std::cout << f.m_marker << std::endl;
    }
}

它会创建dequefoo个对象。第一个对象的标记为"my initial marker",由于createInnertrue,因此它将创建第二个对象。我希望得到以下结果:

Marker is my initial marker
Marker is now my initial marker
There are 2 items in the deque:
my initial marker
my other marker

然而,对于clang ++(tags / Apple / clang-421.11.66)和libc ++(不确定它是什么版本),这就是我得到的:

Marker is my initial marker
Marker is now my other marker
There are 2 items in the deque:
my other marker
 

如您所见,第一个对象的m_marker字段被第二个对象覆盖,而在双端队列中显示的第二个字段现在为空。显然,某处存在一个错误,它必须是在调用deque期间修改emplace_back或者libc ++没有完成其工作时未定义的行为。它是哪一个?

1 个答案:

答案 0 :(得分:2)

正如Howard Hinnant回答on the bug report,标准没有说明这个案例,但需要说它会导致未定义的行为:

  

在每种情况下,由于例外安全考虑,   容器在构造foo之前不会被“改变”   完成。这样,如果foo构造函数抛出容器   国家没有变化。例如,vector.size()直到被改变   foo构造函数完成了。所以当第二个   施工在第一个完工之前开始,它仍然是   附加到零长度向量。

     

这不是可以在实施中解决的问题   容器。标准需要说“不要那样做”。

所以不要指望它适用于任何实现。