我试图理解以下行为:
#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。
答案 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))