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

时间:2015-02-15 17:04:25

标签: c++ c++11 vector

我试图理解以下行为:

#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;
}

事实证明,const的{​​{1}}成员隐含地删除了Foo的{​​{1}}复制赋值运算符。

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

2 个答案:

答案 0 :(得分:6)

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

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

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

答案 1 :(得分:2)

要在向量中插入元素,如果它不是结尾,则应移动所有尾部元素

[1][2][3][4][5]
 |  |  |    \  \ 
[1][2][3][6][4][5]

因此,需要移动或复制构造函数。

http://en.cppreference.com/w/cpp/container/vector/insert

您仍然可以将循环转换为

copy(first, last, back_insterter(v1))