3

我正在使用emplace_back将项目添加到std::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;
    }
}

它创建了一个deque对象foo。第一个对象的标记是"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在调用期间修改 a 是未定义的行为emplace_back,或者 libc++ 没有完成它的工作。哪一个?

4

1 回答 1

2

正如 Howard Hinnant在错误报告中回答的那样,该标准没有说明这种情况,但需要说明它会导致未定义的行为:

在每种情况下,出于异常安全考虑,容器不会“更改”,直到 foo 的构造完成。这样,如果 foo 构造函数抛出,容器状态不变。例如 vector.size() 在 foo 构造函数完成之前不会改变。因此,当第二个构造在第一个构造完成之前开始时,它仍然附加到一个长度为零的向量。

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

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

于 2013-06-06T15:52:14.283 回答