为什么不能分配给自己缺少复制操作符的对象向量?

Vio*_*ffe 11 c++ vector stdvector c++11

我有一个可复制构造的结构向量,但不可赋值:

struct Struct
{
    inline Struct(const std::string& text, int n) : _text(text), _n(n) {}
    inline Struct(const Struct& other) : _text(other._text), _n(other._n) {}

    const std::string _text;
    const int _n;

    Struct& operator=(const Struct&) = delete;
};
Run Code Online (Sandbox Code Playgroud)

一切都很好.事实上,我甚std::vector<Struct>至可以将值作为函数的返回值传递.然而,这失败了:

std::vector<TextFragment> v1, v2;
v2 = v1;
Run Code Online (Sandbox Code Playgroud)

当然,错误是:

错误:C2280:'Struct&Struct :: operator =(const Struct&)':尝试引用已删除的函数

我不明白为什么它试图调用它.这是否是某种优化以避免重新分配向量的内存块?

How*_*ant 5

这是为了避免重新分配向量的内存块的某种优化吗?...

几乎。这是一种优化,可以避免重新分配vector's 中可能存在的任何内存块value_type。也就是说,这是一个全局假设,即赋值比销毁后复制构造更有效。

例如,考虑vector<string>分配,对于两个相同大小的vectors,以及string中每个点的一堆相同大小的s vector

v2 = v1;
Run Code Online (Sandbox Code Playgroud)

所有这些操作所要做的就是memcpy每个string. 根本没有分配。减少分配/解除分配是当今存在的最重要的优化之一。

但是,您的Struct. 您想要做的是指示vector您不想分配您的Structs,而是销毁它们,然后从v1. 这样做的语法是:

v2.clear();
for (const auto& x : v1)
    v2.push_back(x);
Run Code Online (Sandbox Code Playgroud)

正如下面的评论中所指出的,您还可以复制构造v1,然后swap复制。您要么需要创建 的临时本地副本v1,要么需要v1在成员交换的“lhs”上使用:

std::vector<Struct>(v1).swap(v2);
Run Code Online (Sandbox Code Playgroud)

我个人觉得这很难阅读。在 C++11/14 中,我更喜欢这种涉及移动分配的替代方案:

v2 = std::vector<Struct>(v1);
Run Code Online (Sandbox Code Playgroud)

这些替代品在眼睛上更容易。但是第一种选择,使用clear()push_back平均而言将是最有效的。这是因为第一个选择是唯一有机会capacity()v2. 另外两个总是capacity()在副本中重新创建新的v1并丢弃v2现有的capacity()

  • @TemplateRex:`vector&lt;T&gt;::insert` 要求 `T` 是 MoveAssignable(在这个特定的例子中,也是 CopyAssignable),而 `Struct` 不是。 (2认同)