Why std :: vector requires the = operator

I have a question about a class that we can store in a vector. What requirement can be saved in a vector? It seems that such a class should have an assignment operator. But I'm not sure if all this or not.

Let me give you an example. class A has a const int member. If I do not write operator =, it does not compile. But in this example, this statement does nothing. This program displays 10 and 20 correctly. The = operator seems to be required, but not actually used.

#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
source share
4 answers

This may surprise you:

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

There are aspects of the vector itself that require assignability, although I don’t know, because (and I can’t say compiling your code since my compiler does not complain when I delete operator=() ). According to Wikipedia (which refers to the relevant part of the '03 standard), elements must be CopyConstructible and Assignable .

EDIT: Coming back to this in a day, it seems that the forehead is spanking obvious when std::vector requires Assignable - anytime it has to move elements around. Add a call to v.insert() or v.erase() , for example, and the compilation fails.

+4
source

push_back on the vector will make the vector grow in memory, which means old objects must be copied to the new object using the assignment operator = so you need the assignment operator =.

+2
source

If I do not write operator =, it does not compile.

This surprised me, so I looked at the standard and I found:

Your example has an implicitly deleted copy instance, but it should still compile if the appropriate C ++ 11 standard library is at hand.

The only expression that places restrictions on the type used by vector in your example is push_back .

The push_back() method of the container type of sequence X<T,A> with dispenser A and value_type T requires T :

  • CopyInsertable if a lvalue or const rvalue reference is passed
  • MoveInsertable if non-constant r value is passed

This means that this requires a valid copy constructor or (as in this case) a valid move constructor that will be implicitly present in your code. Therefore, compilation should not be interrupted in any compiler with a valid C ++ 11 standard library.

Operations that require the type contained in vector for assignment:

Auxiliary conditions

 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 

Pessimistic * list of operations

The operations that require T to be assigned if X is vector are:

 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 

* = Pessimistic means that for the actual entry into force, certain conditions may exist for several requirements. If you use one of the expressions listed above, your type T will probably need to be assigned.

+1
source

The availability of the copy constructor and assignment operator is guaranteed by the compiler if you do not create your own. (the correct implementation by default is a completely different story). In your example, you almost do not need to overload A :: opeartor = ().

The problem here is not the "missing" operator = (), but cannot be used by default since you declared the const data member

 const int a_; 

The default compiler operator = () cannot assign a value to the const member. Therefore, you need to overload yourself:

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

So, your version of A :: operator = (), which does nothing, although it compiles the code, does not change the value of a_ in the left operand,

-one
source

Source: https://habr.com/ru/post/1492446/


All Articles