Seriously, if someone hands you a bunch of C/C++ code and you don’t know where to even start getting to grips with this thing….
…run around sprinkling const everywhere. Add a const, compile, if it compiles for all variants and the tests run, great, commit. If it doesn’t, revert and constified the dependencies if you can.
Repeat until you have had a bit of poke around every corner of the code.
Now you have some powerful documentation all over the code. ie. The API’s now tell what doesn’t get mangled.
If it’s ruby code… add a “freeze” at the end of a constructor (def initialize). If the tests run, commit. If not, revert.
I’m wondering if it makes sense to ever have a method that accepts const X* p, tho (as opposed to const X* const p). What would we change that pointer to?
I’m a little rusty on the details here but I think this is right: in the const X* p case, you get a copy of the pointer and could conceivably still do mutating pointer arithmetic on it. It won’t affect the caller’s copy of the pointer, but could readily result in you operating on memory you didn’t intend to. By adding the extra const, you’re putting up another guard rail that says “I’m only accessing the single object pointed at and don’t want to access other instances nearby in memory”
The benefit of const correctness is that it prevents you from inadvertently modifying something you didn’t expect would be modified
No it doesn’t, unfortunately, though it makes it difficult. The problem with const in C/C++ is that it’s a property of the reference, not a property of the object (with the exception of global variables declared const). This means that it is completely valid to have something like this:
int x(int *, const int *);
...
int a;
x(&a, &a);
Here, the const and non-const parameters alias and so even though the object can’t be mutated via the const pointer, it can be mutated out from under you via a reference that you hold. For any non-trivial object graph, it’s quite easy to introduce this kind of accidental aliasing.
This is unfortunate both for the programmer (these bugs are hard to find) and also for the compiler: A load of optimisations would be possible if you had the invariant that an object can’t be mutated while a const pointer exists to it.
C++ also has the quite terrifying mutable keyword, which is used to define a field that may be modified in a const method. This is useful for caches and other things that don’t affect publicly visible state but has a similar effect on optimisation.
Seriously, if someone hands you a bunch of C/C++ code and you don’t know where to even start getting to grips with this thing….
…run around sprinkling const everywhere. Add a const, compile, if it compiles for all variants and the tests run, great, commit. If it doesn’t, revert and constified the dependencies if you can.
Repeat until you have had a bit of poke around every corner of the code.
Now you have some powerful documentation all over the code. ie. The API’s now tell what doesn’t get mangled.
If it’s ruby code… add a “freeze” at the end of a constructor (def initialize). If the tests run, commit. If not, revert.
Repeat until.
This is a goldmine of good advices with C++.
I’m wondering if it makes sense to ever have a method that accepts
const X* p, tho (as opposed toconst X* const p). What would we change that pointer to?I’m a little rusty on the details here but I think this is right: in the
const X* pcase, you get a copy of the pointer and could conceivably still do mutating pointer arithmetic on it. It won’t affect the caller’s copy of the pointer, but could readily result in you operating on memory you didn’t intend to. By adding the extra const, you’re putting up another guard rail that says “I’m only accessing the single object pointed at and don’t want to access other instances nearby in memory”I think…
Exactly that :) I’m trying to think of sane implementations of any method, where I would like to modify the pointer to a const object.
I’m super late to the game, but if you were passed an array of objects as a pointer, you could iterate through them by incrementing. I guess.
No it doesn’t, unfortunately, though it makes it difficult. The problem with
constin C/C++ is that it’s a property of the reference, not a property of the object (with the exception of global variables declaredconst). This means that it is completely valid to have something like this:Here, the
constand non-constparameters alias and so even though the object can’t be mutated via theconstpointer, it can be mutated out from under you via a reference that you hold. For any non-trivial object graph, it’s quite easy to introduce this kind of accidental aliasing.This is unfortunate both for the programmer (these bugs are hard to find) and also for the compiler: A load of optimisations would be possible if you had the invariant that an object can’t be mutated while a
constpointer exists to it.C++ also has the quite terrifying
mutablekeyword, which is used to define a field that may be modified in aconstmethod. This is useful for caches and other things that don’t affect publicly visible state but has a similar effect on optimisation.