0

I know that use of const_cast won't introduce undefined behaviour (i.e., it's safe to use), as long as the variable you're const_casting wasn't originally defined as const or if it was originally defined as const you're not modifying it via its const_casted alias.

However, It is also known that most STL containers (e.g., std::vector, std::set), allocate their internal buffers dynamically. Based on this fact I think that is impossible for a const defined std::vector to be placed in read-only memory.

Naturally, if the above holds I come to the assumption that such kind of STL containers even if they're defined as const, e.g.,:

std::vector<int> const v;

const_casting them and altering them via their const_casted alias is legitimate and won't cause any undefined behavior.

Does the above assumption holds or I'm wrong?

101010
  • 41,839
  • 11
  • 94
  • 168
  • 7
    If the standard says it is UB, it is UB. Optimizers use this to do all kind of crazy stuff that assumes `const` objects won't be modified. – juanchopanza Jan 26 '16 at 12:41
  • Notice, that in case of constant vector, compiler is not required to dynamically allocate memory (_avoiding allocation_ standard clause) and, in fact, it is possible to place constant vector completely in static read-only memory. – Revolver_Ocelot Jan 26 '16 at 13:05
  • @101010 I think you selected my answer as "solution" a little too fast. It is not yet (as I'm writing this) a real answer to your question. So far I've just addressed the assumption that dynamically allocated memory must necessarily be mutable. – Cheers and hth. - Alf Jan 26 '16 at 13:23
  • 1
    If you want an object to be modifiable, don't say that it's not. – Pete Becker Jan 26 '16 at 13:43

1 Answers1

4

The C++ standard explicitly points out that casting away const for an object created via new const T, and modifying it, is Undefined Behavior.

E.g., the C++11 standard contains this example in its §7.1.6.1/4:

const int* ciq = new const int (3); // initialized as required
int* iq = const_cast<int*>(ciq); // cast required
*iq = 4; // undefined: modifies a const object

Examples in the standard are non-normative, just examples, and can be wrong. For example, in C++03 nearly all examples that used <iostream> were wrong (at that time it was formally necessary to also include <ostream>, but that was not the intention of the committee), and the expression examples in C++03 §5/4 were wrong, saying the behavior was unspecified rather than undefined (which might have reflected an original intention). However, the above example is correct.

This shows that dynamically allocated memory needs not be mutable: that modifying it, can have Undefined Behavior.

However, when e.g. a std::string is created, its allocation of a buffer (if any) occurs during execution of a constructor, at which point the object is not yet const, and the buffer is not allocated as const. So the buffer, if one is allocated, is not originally const. But regarding this particular example the std::string may use the small buffer optimization where it uses storage directly in the object, which would then be originally const (potentially allocated in read only memory). And this goes to the rational for the rule that no originally const object can be modified.


In addition to the read-only memory scenario, the rationale for UB includes that it can give compilers optimization possibilities.

As juanchopanza notes in a comment to the question,

Optimizers use this to do all kind of crazy stuff that assumes const objects won't be modified.

Breaking the assumptions of the optimizer by modifying an originally const object, can have disastrous and effectively unpredictable consequences.

Community
  • 1
  • 1
Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331