Does C++11 allow vectorconst T?
No, I believe the allocator requirements say that T can be a "non-const, non-reference object type".
You wouldn't be able to do much with a vector of constant objects. And a const vector<T>
would be almost the same anyway.
Many years later this quick-and-dirty answer still seems to be attracting comments and votes. Not always up. :-)
So to add some proper references:
For the C++03 standard, which I have on paper, Table 31 in section [lib.allocator.requirements] says:
T, U any type
Not that any type actually worked.
So, the next standard, C++11, says in a close draft in [allocator.requirements] and now Table 27:
T, U, C any non-const, non-reference object type
which is extremely close to what I originally wrote above from memory. This is also what the question was about.
However, in C++14 (draft N4296) Table 27 now says:
T, U, C any non-const object type
Possibly because a reference perhaps isn't an object type after all?
And now in C++17 (draft N4659) it is Table 30 that says:
T, U, C any cv-unqualified object type (6.9)
So not only is const
ruled out, but also volatile
. Probably old news anyway, and just a clarification.
Please also see Howard Hinnant's first-hand info, currently right below.
const vector implies const elements?
The first version
v[0].set (1234);
does not compile because it tries to change the vector's first element returned to it by reference. The compiler thinks it's a change because set(int)
is not marked const
.
The second version, on the other hand, only reads from the vector
(*v[0]).set(1234);
and calls set
on the result of the dereference of a constant reference to a pointer that it gets back.
When you call v[0]
on a const
vector, you get back a const
reference to A
. When element type is a pointer, calling set
on it is OK. You could change the second example to
v[0]->set(1234);
and get the same result as before. This is because you get a reference to a pointer that is constant, but the item pointed to by that pointer is not constant.
Why can't I push_back to a vector of const elements?
According to this answer (with commentary from one of the C++11 designers), std::vector<const T>
is not permitted by the Standard.
The answer suggests that it might be possible to supply a custom allocator which permits a vector with that allocator to hold const objects.
You're probably better off not attempting to do this.
Casting vectorint to const vectorconst int
You cannot cast a std::vector<int>
to const std::vector<const int>
.
Besides, it does not make sense to use a std::vector<const int>
at all. It doesn't give you any more safety than a const std::vector<int>
.
Not only that, C++ does not allow construction of std::vector<const T>
. See Does C++11 allow vector<const T>? for more info.
vector of const pointers?
The vector is probably the only container that requires the elements to be copy assignable. This is because the elements are guaranteed to be stored contiguously in memory. So if you exceed the capacity, a new chunk has to be allocated and elements re-assigned. You cannot do this with const
elements.
Same error if you try std::vector<const int>
, or in fact any const
type.
Why does const vectorconst pair... give an 'cannot be overloaded' error?
This is what I could gather so far from the standard and documentation:
std::vector
is an allocator-aware container.
As per C++17 (final working draft N4659)
20.5.3.5 Allocator requirements
[allocator.requirements]
Table 30 says:
T, U, C any cv-unqualified object type (6.9)
For std::vector
it is also required that element type is a complete type and meets the requirements of Erasable.
From [container.requirements.general]/15
we have:
Given an allocator type A and given a container type X having a
value_type identical to T and an allocator_- type identical to
allocator_traits<A>::rebind_alloc<T>
and given an lvaluem
of typeA
,
a pointerp
of typeT*
, an expressionv
of type (possibly const)T
,
and an rvaluerv
of typeT
, the following terms are defined.
...
(15.6) — T is Erasable from X means that the following expression is
well-formed:allocator_traits<A>::destroy(m, p)
Since element type in the question is const
qualified, it fails to meet the requirements.
Why does a const std::vector apply const to the contained objects?
Const-ness in C++ is a semantic concept that means "the observable state of this object cannot be changed using this name." In the case of a vector, its contents are considered part of its observable state, so if the vector is const then its elements necessarily are also const.
This also means you can give some other code a const reference to your vector and have some certainly that it's not going to change the vector on you (reference made explicit here for illustration):
std::vector<int> a = create_a_vector();
std::vector<int> const & b = a;
something_else(b);
Unless something_else()
is deviously going to cast away the const qualifier, you can be sure that it won't be mutating the vector or its contents in any way.
If the type worked as you proposed, you would have to copy the vector:
std::vector<int> a = create_a_vector();
std::vector<const int> b = a;
something_else(b);
If the vector is huge, this would have quite a big impact on performance.
Addendum: The crux of the question seems to be "why are the contents of the vector part of the observable state?"
The best way I can explain this is to illustrate it through the following questions:
- If you copy a vector, do the elements get copied?
- If you compare two vectors for equality, are the elements compared, or just the properties of the vector (the size)?
If the answers to these questions are "yes" then the elements themselves are also part of the observable state. So, this establishes a kind of rule: whatever gets copied during copy-construction/assignment or compared during an equality test is part of the observable state of an object.
For vector, the answers are "yes." Therefore, the elements are considered part of the observable state of the vector, and they must be considered const if the vector itself is const.
Contrast this with std::unique_ptr
. Only the pointer value itself is part of the observable state; the pointer value of a const std::unique_ptr<int>
cannot be mutated, but the pointer target can. This makes sense, because:
- (You can't copy a
std::unique_ptr
, so we can't consider this part of the test.) - If you compare two
std::unique_ptr
s for equality, only the pointer value is actually compared; the value of the target is not.
Therefore, for std::unique_ptr
, the value of the target is not part of the observable state and the const-ness of the std::unique_ptr
object is irrelevant with regards to whether the pointer target can be mutated.
Related Topics
Why Do C and C++ Compilers Allow Array Lengths in Function Signatures When They'Re Never Enforced
Why Is There No Call to the Constructor
Advantage of Switch Over If-Else Statement
How to Detect Reliably MAC Os X, Ios, Linux, Windows in C Preprocessor
When I Change a Parameter Inside a Function, Does It Change For the Caller, Too
Testing Stream.Good() or !Stream.Eof() Reads Last Line Twice
Defining Static Members in C++
How to Declare Two Variables of Different Types in a For Loop
How to Use Enums as Flags in C++
Initialize Static Variables in C++ Class
Are There Any Valid Use Cases to Use New and Delete, Raw Pointers or C-Style Arrays With Modern C++
A Confusing Detail About the Most Vexing Parse
How to Implement an Stl-Style Iterator and Avoid Common Pitfalls
What Happens When I Print an Uninitialized Variable in C++
Can You Use 2 or More or Conditions in an If Statement