Unexpected compilation issue with g ++ -std = C ++ 0x

I have some compilation problems returning elements of type T to a vector when compiling with g ++ -std = C ++ 0x.

This is a minimal example:

#include <vector> using namespace std; class A { public: A() { } A& operator=(A &orig) { return *this; } }; int main(int argc, char **argv) { A a; vector<A> b; A c = a; // This is fine b.push_back(a); // This is not, but only when compiling with -std=c++0x! return 0; } 

It compiles fine with g ++ -Wall -pedantic, but it gives this error when compiling with g ++ -Wall -pedantic -std = C ++ 0x:

  In file included from /usr/include/c++/4.4/vector:69, from min.cpp:1: /usr/include/c++/4.4/bits/vector.tcc: In member function 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]': /usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]' min.cpp:20: instantiated from here /usr/include/c++/4.4/bits/vector.tcc:314: error: no match for 'operator=' in '__position.__gnu_cxx::__normal_iterator<_Iterator, _Container>::operator* [with _Iterator = A*, _Container = std::vector<A, std::allocator<A> >]() = ((const A&)((const A*)std::forward [with _Tp = const A&](((const A&)((const A*)__args#0)))))' min.cpp:11: note: candidates are: A& A::operator=(A&) In file included from /usr/include/c++/4.4/vector:61, from min.cpp:1: /usr/include/c++/4.4/bits/stl_algobase.h: In static member function 'static _BI2 std::__copy_move_backward<true, false, std::random_access_iterator_tag>::__copy_move_b(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]': /usr/include/c++/4.4/bits/stl_algobase.h:595: instantiated from '_BI2 std::__copy_move_backward_a(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]' /usr/include/c++/4.4/bits/stl_algobase.h:605: instantiated from '_BI2 std::__copy_move_backward_a2(_BI1, _BI1, _BI2) [with bool _IsMove = true, _BI1 = A*, _BI2 = A*]' /usr/include/c++/4.4/bits/stl_algobase.h:676: instantiated from '_BI2 std::move_backward(_BI1, _BI1, _BI2) [with _BI1 = A*, _BI2 = A*]' /usr/include/c++/4.4/bits/vector.tcc:308: instantiated from 'void std::vector<_Tp, _Alloc>::_M_insert_aux(__gnu_cxx::__normal_iterator<typename std::_Vector_base<_Tp, _Alloc>::_Tp_alloc_type::pointer, std::vector<_Tp, _Alloc> >, _Args&& ...) [with _Args = const A&, _Tp = A, _Alloc = std::allocator<A>]' /usr/include/c++/4.4/bits/stl_vector.h:741: instantiated from 'void std::vector<_Tp, _Alloc>::push_back(const _Tp&) [with _Tp = A, _Alloc = std::allocator<A>]' min.cpp:20: instantiated from here /usr/include/c++/4.4/bits/stl_algobase.h:561: error: no match for 'operator=' in '* -- __result = std::move [with _Tp = A&](((A&)(-- __last)))' min.cpp:11: note: candidates are: A& A::operator=(A&) 

So it seems that he does not find the correct operator = from A. Why? Why does it point with _Iterator = A* when I skip A?

+8
c ++ c ++ 11
source share
3 answers

The assignment requirement imposed by the language standard for standard container elements requires the expression t = u , even if u is a const object. The requirement was defined in this way, since C ++ 98 (see 23.1 / 4)

You have violated this requirement because your assignment operator does not accept const objects. This immediately means that your class A cannot be used as the type of a container element.

Why this worked in C ++ 03, it does not matter. It worked by accident. The error message shows that the implementation of the C ++ 0x library of the library uses some specific functions of C ++ 0x (for example, std::move ), which makes the above requirement come into play. But in any case, the C ++ 03 implementation (and even the C ++ 98 implementation) may also not compile for your A

Your example with A c = a; it doesnโ€™t matter since it doesnโ€™t use the assignment operator at all (why is it here?).

To fix the error, you must either accept the parameter by reference const, or by value.

+15
source share

I am sure this is a security feature. Types with copy-assignment operator (or copy constructor) that can mutate the right side are unsafe for use in standard containers - an example of this (now deprecated) std::auto_ptr , which will be badly broken if it is stored in a container.

The old C ++ 03 library implementation allowed such unsafe code, but apparently they implemented compile-time checking in the C ++ 0x version - possibly in combination with the ability to move containers.

+3
source share

Standard definition of copy-destination operator (section [class.copy] ):

The user copy assignment operator X::operator= is a non-static function without an X class template with exactly one parameter of type X , X& , const X& , volatile X& or const volatile X& .

But the X& and volatile X& options may not be compatible with containers if the assignment can be made from the rHS value of RHS.

NOTE. Passing by value, for example. X::operator=(X) is a fundamental part of the copy and swap idiom.

+1
source share

All Articles