views:

553

answers:

9

This question is from a C# guy asking the C++ people. (I know a fair bit of C but only have some general knowledge of C++).

Allot of C++ developers that come to C# say they miss const correctness, which seems rather strange to me. In .Net in order to disallow changing of things you need to create immutable objects or objects with read only properties/fields, or to pass copies of objects (by default structs are copied).

Is C++ const correctness, a mechanism to create immutable/readonly objects, or is there more to it? If the purpose is to create immutable/readonly objects, the same thing can be done in an environment like .Net.

+7  A: 

const correctness in C++ is at heart simply a way of saying exactly what you mean:

void foo( const sometype & t ) {
   ...
}

says "I will not change the object referred to by t, and if I try to, please Mr. Compiler warn me about it".

It is not a security feature or a way of (reliably) creating read-only objects, because it is trivial to subvert using C-style casts.

anon
You can also bypass const using the much safer const_cast. Personally, I'd outright ban C-style casts in my code.
Chris Jester-Young
const_cast is there not to be used. Only as a safety net for old-badly written libraries. It is a clear symptom of a bad design if you need it, and it is unsafe to use in some cases.
David Rodríguez - dribeas
+4  A: 

With const-correctness, you can expose a mutable object as read-only without making a copy of it and wasting precious memory (especially relevant for collections). I know, there is this CPU-and-memory-are-cheap philosophy among desktop developers, but it still matters in embedded world.

On top of that, if you add complexities of memory ownership in C++, it is almost always better not to copy non-trivial objects that contain or reference other objects, hence there is a method of exposing existing objects as read-only.

Alex B
+13  A: 

A whole section is devoted to Const Correctness in the FAQ. Enjoy!

dirkgently
I've read the FAQ you linked, and after reading it I've realized, const correctness is needed in a pointer based language that doesn't have automatic memory management and less needed (or at all) in a reference based language like C# (that employs other methodologies to enforce read only behavior)
Pop Catalin
as I pointed out in my anser - the issue is not enforcement, it is being clear in what your code means
anon
@Pop Catalin: go over it again. Const correctness has nothing to do with pointer/reference approaches but with providing extra invariants to the functions.
David Rodríguez - dribeas
@Pop Catalin: In addition to what people have pointed out, you may also be interested in a post I made to another question on SO <http://stackoverflow.com/questions/655027/when-should-a-member-function-be-both-const-and-volatile-together/655048#655048>. Hopefully, it will aid your understanding.
dirkgently
+5  A: 

I bet this is a matter of mindsets. I'm working myself with long-time C++ people and have noticed they seem to think in C++ (of course they do!). It will take time for them to start seeing multiple answers to the ones they've grown familiar to have the 'stock' answers like const correctness. Give them time, and try to educate them gently.

Having said that, I do like the C++ 'const' way of guarantees. It's mainly promising the user of an interface that the object, data behind the pointer or whatever won't be messed with. I would see this as the #1 value of const correctness. #2 value is what it can allow the compiler in terms of optimization.

The problem is, of course, if the whole sw stack hasn't been built with const in mind from the ground up.

I'm sure C# has its own set of paradigms to do the same. This shows why it's so important to "learn one new (computing or natural) language a year". Simply to exercise one's mind of the other ways to see the world, and solve its problems.

akauppi
+1  A: 

Just enlisting the compiler's help when writing code would be enough for me to advocate const-correctness. But today there is an additional advantage: multi-threading code is generally easier to write when you know where can our objects change and where they cannot.

Gorpik
+2  A: 

C++ provides plenty of ways you can mess up your code. I see const correctness as a first, efficient way of putting constraints to the code, in order to control the "side" effects (unwanted changes).

Marking a parameter as const (usually reference to const object or pointer to const object), will ensure that the passed object can't be changed, so you have no "side" effect of that function/method.

Marking a method as const will guarantee that that method will not change the state of the object it works with. If it does, the compiler will generate an error.

Marking a const data member will ensure that the data member can only be initialized in the initialization list of the constructor and can't be changed.

Also, smart compilers can use the constness as hints for various performance optimizations.

Of course, you can override constness. Constness is compile time checking. You can't break the rules by default, but you can use casting (e.g. const_cast) to make a const object non-const so it can be changed.

Cătălin Pitiș
+3  A: 

Excellent Scott Meyer's book Effective C++ has dedicated an item to this issue:

ITEM 3: Use const whenever possible.

It really enlightens you :-)

fco.javier.sanz
+3  A: 

The real answer, even if it is really hard to grasp if you have not used it, is that you loose expressiveness. The language has concepts that you cannot possibly express in C#, and they have meaning, they are part of the design, but lost in the translation to code.

This is not an answer, but rather an example:

Consider that you have a container that is sorted on a field of the elements that are stored. Those objects are really big. You need to offer access to the data for readers (consider showing the information in the UI).

Now, in C#/Java, you can go in one of two ways: either you make a copy for the caller to use (guarantees that the data will not change, but inefficient) or you return a reference to your internally held object (just hoping the caller will not change your data through setters).

If the user gets the reference and changes through it the field that serves as index, then your container invariants are broken.

In C++ you can return a constant reference/pointer, and the compiler will disable calling setter methods (mutating methods) on the instance you return. You get both the security that the user will not change (*) and efficiency in the call.

The third not mentioned before option is making the object inmutable, but that disables changes everywhere. Perfectly controlled changes to the object will be disallowed, and the only possibility of change is creating a new element with the changes performed. That amounts to time and space.

David Rodríguez - dribeas
+2  A: 

I think it's a pity C# doesn't support const correctness as C++ does. 95% of all parameters I pass to a function are constant values, the const feature guarantees that the data you pass by reference won't be modified after the call. The "const" keyword provides compiler-checked documentation, which is a great help in large programs.

Dimitri C.