9

The following doesn't compile (very verbose error, but basically "cannot be overloaded" and "invalid conversion from 'const void*' to 'void*'"). I can understand why for example push_back() may not compile, as you can't copy/move into a Foo* const, but why doesn't this compile:

#include <vector>
using namespace std;

class Foo;

int main()
{
  vector<Foo* const> vec;
}
Agrim Pathak
  • 3,047
  • 4
  • 27
  • 43
  • 1
    Full error can be found [here](http://ideone.com/EouxNT) – Fantastic Mr Fox Mar 31 '15 at 21:06
  • In C++03 vector element had to be CopyAssignable. In C++11 it is still not allowed, [see here](http://stackoverflow.com/questions/6954906/does-c11-allow-vectorconst-t). In fact I'd suggest closing as duplicate of that question if everyone agrees. – M.M Mar 31 '15 at 21:13
  • How do you think you could insert new elements in the `vector` ? – Jagannath Mar 31 '15 at 23:30
  • I was hoping there existed a solution using casts. Didn't know the language forbid it. – Agrim Pathak Apr 01 '15 at 00:26

4 Answers4

14

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.

vsoftco
  • 55,410
  • 12
  • 139
  • 252
  • 2
    Why does reallocation need assignment? Sounds more like it needs copyability... – Kerrek SB Mar 31 '15 at 21:08
  • @KerrekSB: From the point of view of the compiler assignment and copyability boil down to the same thing. – datenwolf Mar 31 '15 at 21:10
  • Not any const-qualified type; it should work when the assignment operator is const. –  Mar 31 '15 at 21:10
  • I actually meant copy-assignable, but I think the idea is the same. edited the answer. – vsoftco Mar 31 '15 at 21:11
  • @райтфолд but how can the `operator=` be ever `const`? – vsoftco Mar 31 '15 at 21:12
  • 1
    @vsoftco simple: `T const& operator=(T const&) const { … }`. –  Mar 31 '15 at 21:12
  • 1
    @райтфолд I know how the decl. will look like, but I find hard to understand how you'd implement it without modifying the "guts" of the vector, maybe declaring members as `mutable`.... – vsoftco Mar 31 '15 at 21:15
  • Although perhaps `std::vector` simply doesn't work with `const` members regardless: http://coliru.stacked-crooked.com/a/be481105c08150ca. Should be looked up in the standard to see whether this is an implementation bug. –  Mar 31 '15 at 21:15
  • @райтфолд I don't think it is, the allocator's typedefs have to match the container's, the container's are what you pass as the type, and the allocator's cannot be `const`. I think there's an _implicit_ requirement that no container can have `const` elements simply because of the allocator requirements. I could very well be wrong though. – Mooing Duck Mar 31 '15 at 21:35
5

You are declaring a vector that contain const pointer of Foo, that mean that the pointer could not be modified. When you insert an element in the vector would need to write to a const pointer (not valid).

You are sure it's not: std::vector<Foo const *> vec; where Foo don't be modified by the pointer could.

NetVipeC
  • 4,402
  • 1
  • 17
  • 19
  • I had similar compilation issue like above and indeed the problem was it should be "Foo const *" which means you can modify the pointer value but the not pointed object! – David Constantine Dec 26 '22 at 11:45
3

Vector elements need to be assignable for many operations: If you insert an element in the middle of the vector, all the later elements have to be re-assigned. Const-qualified types are usually not assignable.

If you don't perform operations that require assignment, you can still use vectors of non-assignable types, though.

However, you may only use std::allocator<T> when T is a non-const object type, so std::vector<const int> is ill-formed.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • Since C++11 vector elements do not need to be assignable – M.M Mar 31 '15 at 21:11
  • @MattMcNabb: Absolutely right, edited. – Kerrek SB Mar 31 '15 at 21:13
  • @MattMcNabb hmmmm, g++4.9.2 and even gcc5 believes otherwise, but yes, you are correct – vsoftco Mar 31 '15 at 21:13
  • @KerrekSB OK; however according to [this question](http://stackoverflow.com/questions/6954906/does-c11-allow-vectorconst-t) the vector is still not permitted – M.M Mar 31 '15 at 21:16
  • In your last sentence, "If you don't perform operations that require assignment, you can still use vectors of non-assignable types, though", doesn't that apply here? I'm not assigning anything to `vec`. – Agrim Pathak Mar 31 '15 at 21:19
  • @AgrimPathak: Sorry, I was on the wrong track. See update. – Kerrek SB Apr 01 '15 at 11:01
1

The C/C++ const keyword is left-associative, i.e. it effects the token to its left, except if const is the first token in a statement. So void *const means "constant (=immutable) pointer to void".

Hence the semantics are:

int a;
void * const ptr = (void*)&a; /* legal */

int b;
ptr = (void*)&b; /* not permitted */

the later is illegal because const variables must be initialized at definition and can not be altered later on.

When writing std::vector<void * const> you're asking the compiler to instance the template as a vector of immutable pointers to void. However immutable means, it can be assigned to only at definition, which however does not fly with the dynamic nature of std::vector.

datenwolf
  • 159,371
  • 13
  • 185
  • 298