views:

473

answers:

8

This is a C++ disaster, check out this code sample:

#include <iostream>

void func(const int* shouldnotChange)
{
    int* canChange = (int*) shouldnotChange;
    *canChange += 2;
    return;
}


int main() {
    int i = 5;
    func(&i);
    std::cout << i;
    return 0;
}

The output was 7!

So, how can we make sure of the behavior of C++ functions, if it was able to change a supposed-to-be-constant parameter!?

EDIT: I am not asking how can I make sure that my code is working as expected, rather I am wondering how to believe that someone else's function (for instance some function in some dll library) isn't going to change a parameter or posses some behavior...

+12  A: 

By writing sane code. If you write code you can't trust, then obviously your code won't be trustworthy. Similar stupid tricks are possible in pretty much any language. In C#, you can modify the code at runtime through reflection. You can inspect and change private class members. How do you protect against that? You don't, you just have to write code that behaves as you expect.

Apart from that, write a unittest testing that the function does not change its parameter.

jalf
It looks like the OP is asking about trusting someone else's code. There's no way to enforce that in the language.
Tom
But you can test it. And of course, don't use third-party code you don't trust. The same applies to any third-party code, even if it doesn't violate const-ness. How can you be sure that a socket send() function does what it claims to do?
jalf
A: 

(int*) is the casting syntax from C. C++ supports it fully, but it is not recommended.

In C++ the equivalent cast should've been written like this:

int* canChange = static_cast<int*>(shouldnotChange);

And indeed, if you wrote that, the compiler would NOT have allowed such a cast.

What you're doing is writing C code and expecting the C++ compiler to catch your mistake, which is sort of unfair if you think about it.

Frederick
Actually in C++ it's const_cast<int*>() and the compiler will let you do it.
Martin York
I know that. But what I presumed was that the poster was blaming C++ for allowing such a cast in such a off-hand way. The only way I could convey that was that, in C++, regular, day-to-day cast has a special syntax and if he'd used it, the compiler would've caught him.
Frederick
+2  A: 

Don't use C style casts in C++.
We have 4 cast operators in C++ (listed here in order of danger)

  • static_cast<>         Safe (When used to 'convert numeric data types').
  • dynamic_cast<>    Safe (but throws exceptions/returns NULL)
  • const_cast<>         Dangerous (when removing const).
  • static_cast<>         Very Dangerous (When used to cast pointer types. Not a very good idea!!!!!)
  • reinterpret_cast<> Very Dangerous. Use this only if you understand the consequences.

You can always tell the compiler that you know better than it does and the compiler will accept you at face value (the reason being that you don't want the compiler getting in the way when you actually do know better).

Power over the compiler is a two edged sword. If you know what you are doing it is a powerful tool the will help, but if you get things wrong it will blow up in your face.

Unfortunately, the compiler has reasons for most things so if you over-ride its default behavior then you better know what you are doing. Cast is one the things. A lot of the time it is fine. But if you start casting away const(ness) then you better know what you are doing.

Martin York
I think your ordering of static_cast and dynamic_cast is arguable. Sure dynamic_cast indicates errors (at least of RTTI is on) and you have to deal with them, but with static_cast you can actually downcast incorrectly and get no runtime error if the cast was incorrect.
Logan Capaldo
That is because static_cast is compile time only. And only valid for objects of similar types. I don't think static_cast<> (An example where I am wrong would be good) will have do enough harm by-itself to cause a crash.
Martin York
note static_cast can be used to cast to void*, and then to any other type. or a base class to any derived, even if it's not of the right type. well, i would call any cast, except dynamic_cast, as unsafe - meaning any cast doesn't care to do something really dangerous
Johannes Schaub - litb
OK. If you use static_cast<> in a stupid way it is as dangerous as a C cast. I have added a qualifier above. Safe when used correctly. Dangerous when used with pointers (but you should not be using it with pointers!).
Martin York
A common idiom is to create a "checked_cast" function which without NDEBUG first performs a dynamic_cast and then a static_cast. Also note, that 'dynamic_cast' is only available where your type has a vtable (ie. a virtual function) and so sometimes you just cannot use it.
Richard Corden
MSalters
+7  A: 

A C-style cast means all bets are off. It's sort of like telling the compiler "Trust me, I know this looks bad, but I need to do this, so don't tell me I'm wrong." Also, what you've done is actually undefined. Casting off const-ness and then modifying the value means the compiler/runtime can do anything, including e.g. crash your program.

Logan Capaldo
Doesn't have to be a C-style cast. reinterpret_cast<int *> or const_cast<int *> would incur the same risk (though at least be greppable).
Tom
+2  A: 

The only thing I can suggest is to allocate the variable shouldNotChange from a memory page that is marked as read-only. This will force the OS/CPU to raise an error if the application attempts to write to that memory. I don't really recommend this as a general method of validating functions just as an idea you may find useful.

Henk
+20  A: 

Based on your edit, your question is "how can I trust 3rd party code not to be stupid?"

The short answer is "you can't." If you don't have access to the source, or don't have time to inspect it, you can only trust the author to have written sane code. In your example, the author of the function declaration specifically claims that the code will not change the contents of the pointer by using the const keyword. You can either trust that claim, or not. There are ways of testing this, as suggested by others, but if you need to test large amounts of code, it will be very labour intensive. Perhaps moreso than reading the code.

If you are working on a team and you have a team member writing stuff like this, then you can talk to them about it and explain why it is bad.

mch
That's exactly what I wanted, thanks :)
Lawand
I'll add that this is true of any language, not just C++.
Rob K
+9  A: 

The general rule in C++ is that the language is designed to protect you from Murphy, not Machiavelli. In other words, its meant to keep a maintainance programmer from accidentally changing a variable marked as const, not to keep someone from deliberatly changing it, which can be done in many ways.

KeithB
+1 I like that mnemonic. Too many developers are worried about intentional subversion of the C++ mechanics, when it's really impossible to address.
Tom
+2  A: 

The simplest way to enforce this would be to just not pass a pointer:

void func(int shouldnotChange);

Now a copy will be made of the argument. The function can change the value all it likes, but the original value will not be modified.

If you can't change the function's interface then you could make a copy of the value before calling the function:

int i = 5;
int copy = i
func(&copy);
Edmund
This is a nice idea
Lawand