VC++ allows to use const types for STL containers. Why?

706 views Asked by At

STL containers require the stored values to be copy constructible and assignable. const T is obviously not an assignable type for any T, but I tried to use it (just being curious) and found out that it compiles and, moreover, behaves as an assignable type.

vector<const int> v(1);
v[0] = 17;

This successfully runs in Visual Studio 2008 and assigns v[0] to 17.

2

There are 2 answers

4
James McNellis On

This is not a bug in the implementation as others have suggested.

Violating the requirements of a C++ Standard Library facility does not render your program ill-formed, it yields undefined behavior.

You have violated the requirement that the value type stored in a container must be copy constructible and assignable (const types are not assignable, obviously), so your program exhibits undefined behavior.

The applicable language from the C++ Standard can be found in C++03 17.4.3.6 [lib.res.on.functions]:

In certain cases (replacement functions, handler functions, operations on types used to instantiate standard library template components), the C++ Standard Library depends on components supplied by a C++ program. If these components do not meet their requirements, the Standard places no requirements on the implementation.

In particular, the effects are undefined in the following cases:

...

  • for types used as template arguments when instantiating a template component, if the operations on the type do not implement the semantics of the applicable Requirements subclause.

The Visual C++ Standard Library implementation may do anything with this code, including silently removing or ignoring the const-qualification, and it is still standards-conforming.

6
Matteo Italia On

This simply shouldn't work. At §23.1 ¶ 3 it's specified, as you said, that objects stored in a container must be CopyConstructible (as specified at §20.1.3) and Assignable.

The Assignable requirements for a type T are that, being t and u of type T, you can do:

t = u

having a T& as return value and t equivalent to u as postcondition. (§23.1 ¶4)

Thus, const types are clearly not Assignable, since doing t = u would raise a compilation error (§7.1.5.1 ¶5).

I suppose that this is a bug in Microsoft implementation. g++ on Linux emits the typical 25 kajillion-lines template error if you even try to instantiate a vector<const int> (tested both with and without the -std=c++0x flag, just in case).

By the way, this is also explained in detail in this IBM FAQ.


In theory, as @James McNellis said, the compiler is not required to blow up on the vector instantiation (if it's undefined behavior anything can happen - including everything working fine); however, on the assignation statement there's a violation of the standard that should produce a compilation error.

In facts, the operator[] member returns a vector<const int>::reference; that one is required to be an lvalue of T (§23.1 ¶5 table 66); since T is of a const type, it will be a const lvalue. So we fall down to (§7.1.5.1 ¶5), which defines code that tries to perform an assignment to a const element as "ill-formed", and this demands a compilation error or at least a warning, because assignment-to-const is a diagnosable rule (§1.4 ¶1-2) (no "no diagnostic is required" statement is specified).


Final edit

Actually, @James McNellis is right; once you've invoked undefined behavior by instantiating vector<const int>, the usual rules stop having value, so the implementation is still standard-conforming whatever it does - including removing the const from the element type or generating the usual nasal demons.