为什么std :: vector :: insert需要复制assign?

Dan*_*iel 5 c++ vector c++11

我试图了解以下行为:

#include <vector>
#include <iterator>    

struct Foo {
    Foo(int a) : a_ {a} {}
    const int a_; // Note the const
};

int main(int argc, char **argv) {
    std::vector<Foo> v1 {Foo {0}};
    std::vector<Foo> v2 {Foo {1}};

    auto first = std::begin(v2);
    auto last  = std::end(v2);

    for (; first != last; ++first) {
        v1.push_back(*first); // Fine
    }

    //v1.insert(v1.begin(), first, last); // Does not compile

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

事实证明,该const成员Foo隐含地删除了使用Foo的副本赋值运算符std::vector::insert.

为什么std::vector::insert需要在std::vector::push_back复制构造时复制赋值?这是否意味着手动连接两个向量可能更有效?这是使用LLVM.

小智 6

从逻辑上讲,没有理由要求赋值运算符.该insert操作可以完全通过移动任何现有元素vec[x]来实现,vec[x+1]通过使用(大致)vec[x+1].~T(); new(&vec[x+1]) T(std::move(vec[x]));循环来销毁现有元素,并使用就地构造来向前移动前一个元素.

然而,一种更自然的写入方法,在精心设计的类中通常至少同样有效,如果不是更有效,则使用赋值:vec[x+1] = std::move(vec[x]);.一个简单的例子,它可以提高效率,如果向量元素的构造和破坏涉及分配和释放内存:使用赋值可以轻松绕过它.

做出了一个决定,允许向量使用赋值运算符比缺点有更多的好处.你的课很不寻常,你的课不会从这个决定中受益.这很不幸,但是没有办法设计出适合每个用例的矢量.

  • @Daniel 更一般并不一定意味着更高效。 (2认同)
  • @Daniel 啊,我明白你现在想说什么了。无论您传递给它什么参数,“插入”方法都需要工作。它可能将赋值运算符与某些参数值一起使用,并且可能不会将它们与其他一些值一起使用,但在编译时不会知道使用哪种方法。是的,Benjamin Lindley 是对的,赋值运算符可能只会出现在一个循环中,在你的情况下,它碰巧执行了零次,这仍然需要它存在,但不会影响性能。 (2认同)