是否允许将std :: vector的元素插入相同的向量? [英] Is inserting an element of a std::vector into the same vector allowed?

查看:286
本文介绍了是否允许将std :: vector的元素插入相同的向量?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以下 std :: vector< T>的 insert emplace 成员函数;

Consider the following insert and emplace member functions of std::vector<T>:

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 开始的所有元素的引用无效,该引用可能包括自变量,或者如果发生重新分配,则对 all 元素的引用,其中肯定包括它,但这是否意味着这样的调用是无效的,还是插入(似乎)首先发生?

What if one of them is invoked with a reference to an element of the vector itself as an argument? Normally, each of them invalidates references to all elements starting from position, which might include the argument, or if a reallocation happens, references to all elements, which definitely include it, but does this mean such an invocation is invalid or does the insertion (seem to) happen first?

看看一些常见的实现会产生奇怪的结果:

Looking at some common implementations gives curious results:


  • libstdc ++在移动任何元素之前复制参数,但仅在 const T& 插入的c $ c>重载。它包含以下注释:

  • libstdc++ copies the argument before moving any elements, but only in the const T& overloads of insert. It contains this comment:


这三个操作的顺序由C ++ 0x
情况决定,可以更改属于
到现有向量的新元素。这仅对于调用者
通过const lvalue ref将该元素作为问题(请参见23.1 / 13)。

The order of the three operations is dictated by the C++0x case, where the moves could alter a new element belonging to the existing vector. This is an issue only for callers taking the element by const lvalue ref (see 23.1/13).

但是C ++ 11§23.1只是容器库的简短摘要,即使我们假设这是指§23.2.1(在C ++ 03中曾经是§23.1),§23.2.1/ 13也仅给出了一个可以识别分配器的容器的定义,这似乎与此无关。我翻阅了第23章,但在任何地方都没有找到任何相关的东西。

But C++11 §23.1 is just a brief summary of the containers library, and even if we assume this refers to §23.2.1 (which used to be §23.1 in C++03), §23.2.1/13 only gives a definition of allocator-aware containers, which seems to have nothing to do with this. I’ve looked through chapter 23, but I haven’t found anything relevant anywhere.

libc ++在移动 emplace ,而在 insert 中,它首先移动元素,但将参数引用转换为指针,并对其进行调整以确保它指向原始元素,但同样,它仅在 const T& 重载中完成所有这些操作。

libc++ creates a temporary before moving any elements in emplace, while in insert it moves elements first but converts the argument reference to a pointer and adjusts it to ensure it points to the original element—but again, it does all this only in the const T& overload.

Visual C ++创建一个复制/临时,然后在所有情况下移动任何元素。

Visual C++ creates a copy/temporary before moving any elements in all cases.

我是否错过了标准定义此行为的地方?为什么我看过的三个C ++库彼此不同?为什么libstdc ++注释说这只是 insert(const_iterator,const T&)的问题?如果该标准不要求它起作用,那么为什么还要麻烦这些库来使其完全起作用呢? (当然,这会花费一些副本和/或移动,而这些副本和/或移动可以避免。)最后,如果我要实现一个类似于 std :: vector 的容器,我应该

Did I miss the place where the standard defines this behaviour? Why do the three C++ libraries I looked at disagree with each other? Why does the libstdc++ comment say it’s only an issue for insert(const_iterator, const T&)? If the standard doesn’t require this to work, why do the libraries ever bother to make it work at all? (Surely this costs some copies and/or moves that could otherwise be avoided.) Finally, if I’m implementing a container that should resemble std::vector, should I make this work?

推荐答案

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

To answer the second question first: the standard explicitly says that the standard library is allowed to assume that when passing something by rvalue reference, that rvalue reference is the only reference to that object. This means that it cannot legally be an element of the vector. The relevant part of C++11 17.6.4.9/1:



  • 如果函数参数绑定到右值引用参数,该实现可以假定
    该参数是对此参数的唯一引用。 ... [注意:如果程序将左值传递给
    xvalue,同时将该左值传递给库函数(例如,通过使用参数
    <$ c调用该函数) $ c> move(x)),该程序实际上是在要求该函数将该左值视为临时值。
    实现可以自由地优化别名检查,如果参数为
    一个左值,则可能需要使用别名检查。 -尾注]

  • If a function argument binds to an rvalue reference parameter, the implementation may assume that this parameter is a unique reference to this argument. ... [ Note: If a program casts an lvalue to an xvalue while passing that lvalue to a library function (e.g. by calling the function with the argument move(x)), the program is effectively asking that function to treat that lvalue as a temporary. The implementation is free to optimize away aliasing checks which might be needed if the argument was an lvalue. —end note ]

这使我们只需要处理 const T& 案例。即使在这种情况下libstdc ++和libc ++有所不同,它们的最终结果是相同的-它们将正确地从传入的对象中进行复制。并且该标准仅规定了行为,而不规定实现。只要他们能达到正确的行为,就可以了。

This leaves us just to handle the const T & case. And even though libstdc++ and libc++ differ in this case, their net result is the same—they will correctly copy from the object passed in. And the standard only prescribes behaviour, not implementation. As long as they achieve the correct behaviour, they're fine.

这篇关于是否允许将std :: vector的元素插入相同的向量?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆