Are const values โ€‹โ€‹in the container actually forbidden?

Why can't I put structures with const values โ€‹โ€‹inside a container like std::vector ? (I understand the technical reason the compiler is reporting, I'm just not sure if the compiler / collection should do it this way)

For example, something very simple:

 struct sample { int const a; }; std::vector<sample> v; v.push_back( sample{12} ); 

This gives an error (at least in GCC) about using remote operator= . But I do not understand why it should use operator= . When creating this vector, you do not need to use the copy operator. If he does not use contour-copying in place of a new one, which is quite acceptable. For example, everything is in order:

 sample a; new (&a) sample{12}; 

Calling the sample destructor is also great. That is, there are enough allowed operations on this type to build a vector, but I can not do this. I thought C ++ 11 with rvalue and move semantics might also help here, but maybe I'm wrong.

What part of the standard specifically prohibits this or is it really a compiler error (unlikely)?

+4
source share
2 answers

My reading of the standard (N3290) states that your push_back valid.

23.2.3 para 16 (Table 101 - Optional operations of the sequence container) says that push_back only requires T to be MoveInsertable .

23.2.1, clause 13 defines MoveInsertable : the following expression should be true: allocator_traits<A>::construct(m, p, v);

20.6.8.2, paragraph 5 indicates that by default (for example, for the default allocator) construct causes the placement of a new one - just like your expectation.

Regards, & amp; rzej

+6
source

So, if you use a compatible compiler / stdlib, it will:

  vector<T>::push_back(T&&) 

to which the temporary sample{12} will be attached, as a result of which it calls the move constructor T in the reserved uninitialized storage element in v.end() , using the temporary parameter. To support this, no constructor or copy assignment is required.

A better way would be to add a constructor to sample , and then you can call:

  v.emplace_back(12) 

which, in addition to being shorter, will also avoid the move constructor.

As others have stated, your compiler / stdlib does not match, upgrades to a newer version.

+2
source

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