将std::向量的元素插入到允许的同一向量中

Is inserting an element of a std::vector into the same vector allowed?

本文关键字:向量 插入 std 元素      更新时间:2023-10-16

考虑std::vector<T>的以下insertemplace成员函数:

template <class... Args> iterator emplace(const_iterator position, Args&&... args);
iterator insert(const_iterator position, const T& x);
iterator insert(const_iterator position, T&& x);
iterator insert(const_iterator position, size_type n, const T& x);

如果其中一个被调用时引用了向量本身的一个元素作为参数,该怎么办?通常,它们中的每一个都会使对从position开始的所有元素的引用无效,这可能包括参数,或者如果发生重新分配,则会使对所有元素的引用失效,这些元素肯定包括参数,但这是否意味着这样的调用无效,或者插入(似乎)是首先发生的?

看看一些常见的实现会得到奇怪的结果:

  • libstdc++在移动任何元素之前复制参数,但仅在insertconst T&重载中复制。它包含以下评论:

    这三个操作的顺序由C++0x决定这种情况下,移动可能会改变属于到现有矢量。这只是呼叫者的问题通过常量左值ref取元素(见23.1/13)

    但C++11§23.1只是容器库的一个简短总结,即使我们假设这是指§23.2.1(过去是C++03中的§23.1),§23.2.1/13也只给出了分配器感知容器的定义,这似乎与此无关。我看了第23章,但没有发现任何相关内容。

  • libc++在移动emplace中的任何元素之前创建一个临时元素,而在insert中,它首先移动元素,但将参数引用转换为指针并进行调整,以确保它指向原始元素——但同样,它只在const T&重载中执行这一切。

  • 在任何情况下,Visual C++都会在移动任何元素之前创建一个副本/临时文件。

我是否错过了标准定义这种行为的地方?为什么我看到的三个C++库彼此不一致?为什么libstdc++注释说这只是insert(const_iterator, const T&)的问题?如果标准不要求它工作,那么图书馆为什么要让它工作呢?(当然,这会花费一些本可以避免的复制和/或移动。)最后,如果我要实现一个类似于std::vector的容器,我应该让它工作吗?

首先回答第二个问题:标准明确表示,允许标准库假设通过右值引用传递某个内容时,该右值引用是对该对象的唯一引用。这意味着它在法律上不能成为矢量的一个元素。C++11 17.6.4.9/1:的相关部分

  • 如果函数参数绑定到右值引用参数,则实现可能会假设此参数是对此参数的唯一引用。。。注意:如果程序将左值强制转换为xvalue,同时将该左值传递给库函数(例如,通过使用参数调用函数move(x)),程序有效地要求该函数将该左值视为临时值。这个实现可以自由地优化消除混叠检查,如果参数为左值-尾注]

这让我们只能处理const T &案件。尽管在这种情况下libstdc++和libc++不同,但它们的最终结果是相同的—他们将正确地从传入的对象中复制。而且该标准只规定了行为,而不是实现。只要他们做出正确的行为,他们就没事。