Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are 'const' values inside a container actually disallowed?

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 uncertain the compiler/collection should be doing it this way)

For example, something quite 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 the deleted operator=. But I don't see why it should be using operator=. It shouldn't need to use the copy operator when constructing this vector. Should it not be using the copy contructor an in-place new, which is perfectly allowed. For example, the following is okay:

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

Calling the destructor of sample is also fine. That is, there are enough allowed operations on this type to construct a vector yet I am unable to do so. I thought C++11 with rvalue's and move semantics may also help here, but perhaps I'm wrong on that.

What part of the standard specifically disallow this, or is indeed a compiler error (unlikely)?

like image 792
edA-qa mort-ora-y Avatar asked Feb 16 '23 12:02

edA-qa mort-ora-y


2 Answers

My reading of the Standard (N3290) says that your push_back is valid.

23.2.3 para 16 (Table 101 — Optional sequence container operations) says that push_back only requires of T that it is MoveInsertable.

23.2.1 para 13 defines MoveInsertable : the following expression shall be valid: allocator_traits<A>::construct(m, p, v);

20.6.8.2 para 5 specifies that by default (e.g., for default allocator) construct calls placement new -- much like your expectation.

Regards, &rzej

like image 165
Andrzej Avatar answered Feb 23 '23 16:02

Andrzej


So if you are using a conformant compiler/stdlib there will be a:

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

overload which the temporary sample{12} will bind to, causing it to call the move constructor of T at the reserved uninitialized storage element at v.end(), using the temporary as a parameter. A copy constructor or assignment should not be needed to support this.

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

 v.emplace_back(12)

which apart from being more succinct will also avoid the move constructor as well.

As others have stated your compiler/stdlib is not conformant, upgrade to a newer version.

like image 33
Andrew Tomazos Avatar answered Feb 23 '23 15:02

Andrew Tomazos