为什么std :: vector需要operator =

时间:2013-07-20 09:04:14

标签: c++ stl

我有一个关于我们可以存储在vector中的类的问题。 可以存储在向量中的要求是什么? 似乎这样的类必须有赋值运算符。但我不确定这是不是全部。

让我举个例子。 A类有const int成员。如果我不写operator =,它不会编译。但在此示例中,此运算符不执行任何操作。该程序正确显示10和20。看起来operator =是必需的,但实际上并未使用。

#include <iostream>
#include <vector>

class A {
 public:
  A(int a) : a_(a) {}
  A& operator =(const A& a2) { return *this;} // Without this, compile fails.
  void print() const {
    std::cerr << a_ << std::endl;
  }
 private:
  const int a_;
};

int main(int argc, char** argv) {
  std::vector<A> v;
  v.push_back(A(10));
  v.push_back(A(20));
  for (const A& a : v) a.print();
}

4 个答案:

答案 0 :(得分:5)

这可能让你感到惊讶:

v.push_back(A(20));
v.push_back(A(10));
std::sort(begin(v), end(v));

向量本身的某些方面需要可分配性,但我不知道,但是(我无法通过编译代码来判断,因为当我删除operator=()时我的编译器不会抱怨)。根据{{​​3}}(参考'03标准的相关部分),元素必须是CopyConstructibleAssignable

编辑:一天之后再回到这一点,当std::vector需要Assignable - 任何时候必须移动元素时,它看起来很明显。例如,添加对v.insert()v.erase()的调用,编译将失败。

答案 1 :(得分:2)

向量上的push_back将使向量在内存中增长,这意味着 需要通过赋值operator =将旧对象复制到新对象 因此你需要赋值运算符=。

答案 2 :(得分:2)

  

如果我不写operator =,则不编译。

这令我感到惊讶,所以我查看了标准,我发现:

您的示例有一个隐式删除的复制构造函数,但如果有一个符合标准的C ++ 11标准库,仍应编译。

对示例中vector使用的类型设置约束的唯一表达式是push_back

具有分配器push_back()X<T,A> A的序列容器类型value_type的{​​{1}}方法需要T

  • CopyInsertable 如果传递左值或常量值参考
  • MoveInsertable 如果传递非const rvalue

这意味着它需要一个有效的复制构造函数或(在本例中)一个有效的移动构造函数,它将隐式存在于您的代码中。因此,编译不应该在任何具有有效C ++ 11标准库的编译器中失败。

要求T中包含的类型可分配的操作:

辅助条件

vector

悲观typdef std::vector<T> X; X a,b; X&& rv; X::value_type t; X::value_type&& u; X::size_type n; X::const_iterator p,q; // p = valid for a, q = valid and dereferencable initializer_list<T> il; [i,j) -> valid iterator-range 操作列表

如果X是*,则需要T可分配的操作是:

vector

Statement Requirement on T a = b; CopyInsertable, CopyAssignable a = rv; MoveInsertable, MoveAssignable a = il; CopyAssignable a.emplace(p, args); MoveInsertable, MoveAssignable a.insert(p, t); CopyAssignable a.insert(p, u); MoveAssignable a.insert(p, n, t); CopyInsertable, CopyAssignable a.insert(p, i, j); EmplaceConstructible[from *i], MoveInsertable, MoveAssignable a.insert(p, il); -> a.insert(p, il.begin(), il.end()); a.erase(q); MoveAssignable a.erase(q1,q2) MoveAssignable a.assign(i,j); Assignable from *i a.assign(il); -> a.assign(il.begin(), il.end()); a.assign(n,t) CopyAssignable =悲观意味着可能存在若干要求实际生效的某些条件。如果您使用上面列出的某个表达式,则可能需要指定类型*

答案 3 :(得分:-1)

如果您不创建任何自己的复制构造函数和赋值运算符,则可以保证它们的可用性。 (默认实现的正确性,虽然是一个不同的故事)。在您的示例中,您几乎不必重载A :: opeartor =()。

这里的问题不是&#34;缺少&#34; operator =(),但是默认值不能使用,因为你声明了一个const数据成员

const int a_;

默认编译器生成的operator =()无法为const成员赋值。所以你必须超负荷自己:

A & A::opeartor=(const A & in)
{
    *const_cast<int*>(&a_) = in.a_; // !!!you are expected to do this.
}

所以,你的A :: operator =()版本尽管没有做任何事情,虽然编译代码但是没有改变左手操作数的a_值,