21

Or is there some other protection against modifying them?

It makes sense if they are in read-only memory - that's the reason for making them const, right?

ST3
  • 8,826
  • 3
  • 68
  • 92
Oleksiy
  • 37,477
  • 22
  • 74
  • 122
  • 5
    See [this answer](http://stackoverflow.com/a/4486356/420683) for an example of `const volatile`, where read-only memory wouldn't make sense. – dyp Aug 05 '13 at 12:30
  • I'm pretty sure that in C#, all usages of a `const` are replaced with their value during compilation, so there's nothing left to be changed. I don't know if that's a .NET-ism, or if it's inherited from C, though. – Bobson Aug 05 '13 at 13:22
  • 3
    @Bobson That is impossible to achieve in C++, because `const` variables may have their value set at runtime. – juanchopanza Aug 05 '13 at 13:24
  • @juanchopanza - Good to know. The differences that exist between various related languages are fascinating. – Bobson Aug 05 '13 at 13:27
  • `const int r = rand();` – Keith Thompson Aug 10 '13 at 01:17

9 Answers9

18

const is a compile time construct and isn't known about at runtime. It is only there to help the programmer reason about his program and to prevent bugs being introduced by altering things that were not supposed to be altered. const tells the compiler that you don't want to allow this variable to be changed, and so the compiler will enforce it.

Tony The Lion
  • 61,704
  • 67
  • 242
  • 415
  • 2
    By “the compiler will enforce it”, I presume you mean that you expect the compiler to issue a diagnostic if source code attempts to modify an object through a const-qualified type, not that the compiler will prevent you from converting a const-qualified type (or pointers to such) to a non-const-qualified type (or pointers to such) and modifying the object through the non-const type, provided such modification is allowed by the C++ standard (as it is in some situations)? – Eric Postpischil Aug 05 '13 at 13:30
12

No they are not required to be. const is compile time, and allow compiler to perform some kind of optimization. However, it is not mandatory that a variable be placed into a read-only memory location.

See this example, which is Undefined Behaviour (Thanks to Dyp for pointing that out):

#include <iostream>

int     main()
{
  const int bla = 42;
  int       *ptr = const_cast<int *>(&bla);

  std::cout << *ptr << std::endl;
  *ptr = 21;
  std::cout << *ptr << std::endl;
}

It will output 42 and 21, but it could also crash.

Now see this one:

#include <iostream>

int     main()
{
  const int bla = 42;
  int       *ptr = const_cast<int *>(&bla);

  std::cout << bla << std::endl;
  *ptr = 21;
  std::cout << bla << std::endl;
}

On my compiler, this output 42 and 42, because the compiler made some optimizations. Note that it could still crash because of *ptr = 21;

Xaqq
  • 4,308
  • 2
  • 25
  • 38
  • 1
    `*ptr = 21;` Undefined behaviour. – dyp Aug 05 '13 at 12:28
  • @DyP Edited. Could you provide me explanations or links explaining with `*ptr = 21` is UB? Isn't `const_cast` a valid construct that would allow the modification of the variable? – Xaqq Aug 05 '13 at 12:30
  • It allows you modification of a variable *if that variable hasn't been declared `const`*. Otherwise, UB: [dcl.type.cv]/4 "Except that any class member declared `mutable` can be modified, any attempt to modify a `const` object during its lifetime results in undefined behavior." – dyp Aug 05 '13 at 12:31
  • As I've said, they *can* be placed in read-only memory, e.g. objects with static storage duration like string literals. Modifying them results in UB, as it depends on the platform and implementation (compiler+linker). "However, it does not affect the memory location of variable." not for your compiler/linker. No requirements in the Standard for this. – dyp Aug 05 '13 at 12:37
  • 1
    @DyP Yeah, I've think about string literal but thought they were an exception. Let me edit, and thank you very much for pointing that out. Learned something today :) – Xaqq Aug 05 '13 at 12:38
  • 1
    The reason why your program doesn't show a difference for memory location / no weird behaviour for `*ptr = 21;` is probably because `bla` is either placed on the stack or in a register on a x86 type architecture; both aren't read-only. – dyp Aug 05 '13 at 12:41
6

There are a lot of cases where it's not possible for the compiler to make a const into read-only memory (assuming there is read-only memory in the system in the first place). In fact, I believe nearly all compilers, as a rule, makes const objects live in regular data (or stack) memory, just like ordinary variables.

The main purpose of const is to declare your intent with the compiler that you do not want to and aren't supposed to change some value. I don't see any reason why compilers can't, under limited circumstances, put const variables in read-only memory. But I also wouldn't rely on this - the standard certainly makes this possible, since it mentions that using const_cast remove const from an object that was originally marked const, and then writing to it is undefined behaviour (so, it doesn't require the compiler to allow the value to be modified after using const_cast to remove the original const - and thus does allow for "Crash because we tried to write to read-only memory").

But consider this:

class X
{
   int x;
  public:
   X(int v) : x(v) {}
}

int c = rand();

const X a(c+1);
const X b(c+2); 

In this case, the compiler can't know the value in c that it got from rand, so it can't initialize a and b at compile time.

Mats Petersson
  • 126,704
  • 14
  • 140
  • 227
  • Sorry, I meant writing to a `const` object that has had `const` removed. I have clarfied what I emant. – Mats Petersson Aug 05 '13 at 12:56
  • Alright :) but I still could be pedantic: `char c; char const& rc = c;` -> `rc` is also a variable, and it's declared `const`. – dyp Aug 05 '13 at 12:58
  • Not sure I understand your pedanticism. `rc` is a `const` reference to `c`, so the same variable as `c` - in this case, it's valid to `const_cast` way the constness and write to the reference, thus altering the original value of `c`. – Mats Petersson Aug 05 '13 at 13:02
  • Indeed, but it could be interpreted as *removing `const` from a variable [`rc`] that was originally marked `const`*. The Standard uses its own terminology and speaks of `const` *objects* instead of variables (or variable declarations). Another example: `new const int{5};` (an object, but I wouldn't consider it a variable) – dyp Aug 05 '13 at 13:05
  • Ok, changed `variable` to `object`. – Mats Petersson Aug 05 '13 at 13:16
  • 2
    It's my experience that [most compilers put `const` objects in read-only memory when those objects can be statically initialized.](http://coliru.stacked-crooked.com/view?id=5f641e5bea30e9974590f0a02b4e4907-c944ac6b0eed3bfc48b1f78a894f6965) – Casey Aug 05 '13 at 15:53
4

The const keyword has two uses:

  1. The well-known "I promise not to modify this object's state"
  2. As a special rule, the compiler may place objects whose definition is const in read-only memory as long as the object has no mutable members (i.e. the entire object is the object's state).

That is why const_cast ist allowed to strip away the const qualifier, but a requirement is that the object definition itself is not const. Wikipedia on const correctness states that "However, any attempt to modify an object that is itself declared const by means of const_cast results in undefined behavior according to the ISO C++ Standard.".

Simon Richter
  • 28,572
  • 1
  • 42
  • 64
  • 1
    "That is why `const_cast` is allowed to strip away the `const` qualifier" I think you mean the right thing, but it looks like (2.) is that reason (which it is not). Bonus: here's the quote for UB directly from the Standard: [dcl.type.cv]/4 "Except that any class member declared mutable can be modified, any attempt to modify a `const` object during its lifetime results in undefined behavior." – dyp Aug 05 '13 at 13:22
3

As far as the standard is concerned, there's no requirement to place const variables into write-protected RAM. const is basically just compiler-enforced documentation.

Practically, if a value can be computed entirely at compile-time, compilers will usually use read-only storage for a const variable. Otherwise, they're placed into the same read-write heaps or stacks as everything else.

Cory Nelson
  • 29,236
  • 5
  • 72
  • 110
3

Not only does the C++ standard not guarantee that const objects are in read-only memory, it would be difficult for an implementation to implement completely, as explained below.

It would be difficult for a C++ implementation to place const objects with automatic storage duration whose addresses are taken in read-only memory. This is because each different object must have a different address (because their pointers must compare unequal). So each such object must be created each time the block it is in is executed.

If a const object’s address is not taken, the compiler can implement the multiple instances of it (in the C++ computational model) using only a single instance in memory (because every instance is identical and does not change). So such an object can be created once at program start-up (likely by loading from a constant-data section of the program file), marked read-only, and left unchanged for the duration of program execution. However, if an object’s address is taken (and used in observable ways), then the compiler must create each separate instance of the object (or somehow “fake” that one instance has multiple addresses). In general, a compiler cannot predict how many executions of a block may exist simultaneously (e.g., when there are recursive function calls). So it cannot create, at program start-up, all the instances of an object that are needed. They must be created on the fly.

Creating objects requires modifying memory, to write the initial values of the objects. Therefore, putting const objects with automatic storage duration in read-only memory would require frequently changing memory from read-only to writeable and back. To create a new object, the program would have to change the read-only memory to writeable memory, write the initial value of a new object, and change the memory back to read-only.

Furthermore, this would give the appearance of read-only memory only for single-threaded programs without signal handlers. Programs with multiple threads of execution or single handlers might be able to observe the memory while it is in the writeable state.

Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312
2

No. Consider a const object with a mutable member. As mentioned const is a compile time construct to help the programmer convey intent.

john.dennis
  • 56
  • 2
  • 7
1

If they were in read only memory, it would prevent const_cast from being useful and meaningful, so code like this would not be possible, passing a const variable to a function with a non-const parameter: -

void print (char * str)
{
    cout << str << endl;
}

int main () 
{
    const char * c = "test text";
    print ( const_cast<char *> (c) );
    return 0;
}

Note that the print function could actually change the value in the originally defined const variable c.

Oleksiy
  • 37,477
  • 22
  • 74
  • 122
TheDarkKnight
  • 27,181
  • 6
  • 55
  • 85
  • 2
    "Note that the print function could actually change the value in the originally defined const variable c": but that would likely make the program crash. – Xaqq Aug 05 '13 at 12:45
  • Absolutely, though that depends on what the change was. If it just nulls the string or keeps within the boundary of the string length then it would be ok. So it 'could' change it, but probably shouldn't. – TheDarkKnight Aug 05 '13 at 12:47
  • 4
    `const_cast` is actually useful to cast away constness that has been added, like `char c = 'x'; char const& crc = c; char& rc = const_cast(crc);` (usually involving function parameters). – dyp Aug 05 '13 at 12:48
  • @Merlin069 I'm not sure what you mean by "keeps within the boundary of the string length", so here, just in case: http://ideone.com/ePAzRA. Feel free to ignore it if I misunderstood :) – Xaqq Aug 05 '13 at 12:51
  • @Xaqq, Nice tool, I hadn't see ideaone. You're right, in that exact case it would fail, but you can do something like this which changes a const casted variable: http://ideone.com/BuKjOf and you'd have to be careful not to change beyond the memory of the original string. – TheDarkKnight Aug 05 '13 at 13:05
1

const is a mark for compiler. During compiling, compiler adds constants into separate group and checks for attempts to change it. If some function tries to do that, you will get compiler error.

However it is possible to trick compiler and change const value using pointers and const_cast but as a result of this you trick not compiler but yourself (or colleague).

As I said, to my friend who've been looking how to change const value. const is not for compiler only, it is much more for developer then compiler, because it shows, what data will not be changed.

ST3
  • 8,826
  • 3
  • 68
  • 92