我有一个关于我们可以存储在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();
}
答案 0 :(得分:5)
这可能让你感到惊讶:
v.push_back(A(20));
v.push_back(A(10));
std::sort(begin(v), end(v));
向量本身的某些方面需要可分配性,但我不知道,但是(我无法通过编译代码来判断,因为当我删除operator=()
时我的编译器不会抱怨)。根据{{3}}(参考'03标准的相关部分),元素必须是CopyConstructible
和Assignable
。
编辑:一天之后再回到这一点,当std::vector
需要Assignable
- 任何时候必须移动元素时,它看起来很明显。例如,添加对v.insert()
或v.erase()
的调用,编译将失败。
答案 1 :(得分:2)
向量上的push_back将使向量在内存中增长,这意味着 需要通过赋值operator =将旧对象复制到新对象 因此你需要赋值运算符=。
答案 2 :(得分:2)
如果我不写operator =,则不编译。
这令我感到惊讶,所以我查看了标准,我发现:
对示例中vector
使用的类型设置约束的唯一表达式是push_back
。
具有分配器push_back()
和X<T,A>
A
的序列容器类型value_type
的{{1}}方法需要T
:
这意味着它需要一个有效的复制构造函数或(在本例中)一个有效的移动构造函数,它将隐式存在于您的代码中。因此,编译不应该在任何具有有效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_值,