tags:

views:

265

answers:

7

I have a place in the code that used to say

const myType & myVar = someMethod();

The problem is that:

  • someMethod() returns const myType

  • I need to be able to change myVar later on, by assigning a default value if the object is in an invalid state. So I need to make myVar to be non-const.

  • I assume I need to make myVar be non-reference as well, right? E.g. myType myVar?

  • What is the C++ "correct" way of doing this const-to-nonconst? Static cast? Lexical cast? Something else?

I may have access to boost's lexical cast, so I don't mind that option, but I'd prefer the non-boost solution as well if it ends up i'm not allowed to use boost.

Thanks!

+1  A: 
const_cast<type without const>()

But, does someMethod() really return const myType? If so, you are making a reference to a temporary -- it will be destroyed and your reference will be bad. Change myVar to non-ref (so it copies) -- no need to declare it const in that case. Or, if someMethod() returns a reference, use the const_cast if you must (but you are changing something that someMethod thought wouldn't change).

Lou Franco
A: 

Try the following

myType& mutableMyVar = const_cast<myType&>(myVar);

In general removing const is a bad idea though. The caller method returned you a reference to a variable it believes will be treated as const. If you violate this assumption by removing the const and modifying the variable you could put either object into a valid state.

It may be legal in your particular case but in general this is something to be avoided

JaredPar
If it's to be avoided, why offer it as an answer???
hasen j
@hasen j, because it's a valid construct that is occasionally necessary. Overall to be avoided but sometimes there is no choice but to do that.
JaredPar
No. This is so bad it is dangerous. If is a const reference being returned then modifying it leads to undefined behavior. If it is being copy back (and thus a temporary) then the lifespan of the object is no longer being extended and the object is destroyed at the statement. Thus leading to undefined behavior.
Martin York
@Martin, so when an OP ask "how do I do X", which is specifically asked for in the question, we should respond "I will never tell you how to do X because it's dangerous"?
JaredPar
Getting a -1 vote for this is completely ridiculous. The OP specifically asked "what is the proper way to get rid of the const". A const_cast is the correct answer. Yes this is dangerous, bad ideas and almost always the wrong thing to do. But it doesn't change the fact that it is indeed the answer to the question.
JaredPar
@JaredPar: He did not ask how to cast away const ness. But answering a question should always be taken within the context of the asked question. This answer is not a good or valid answer to the question, it is allowed by the language but it is not a real answer.
Martin York
@Martin, read the last bullet point by the OP. It specifically asks what is the correct way to cast away const in C++.
JaredPar
+9  A: 

You probably don't need any cast. If you can copy a T, then you can also copy a T const, pathological cases excluded. The copy of the T const need not be a T const itself.

myType myVar = someMethod(); // Creates a non-const copy that you may change.
MSalters
This will invoke the copy constructor will it not? Then V_D_R will not be working with a reference to the object returned by someMethod but rather a copy of it.
theycallmemorty
What is someMethod returning? It's probably a temporary, so in order to keep it around it needs to be copied somewhere.
David Thornley
@theycallmemorty: The original poster stated that the object is returned *by value*, not by reference. The fact that the object is already returned from the function by value (if the original poster is right) immedaitely means that copying that object is a pefectly acceptable thing to do.
AndreyT
@David Thornley: It needs to be copied somewhere, or used to initialize a const reference (just like in the original post). The latter will automatically extend the lifetime of the temporary.
AndreyT
A: 

You can creat an object from the const object using copy constructor or something assignment operator and then modify it.

But I think you would be better off seeing why the function was returning const type in the first place. There would have been a reason why it was declared const. If you are very sure that that is what you wanted, you can always const_cast away the constness like this:

T obj1 = const_cast<T&> (obj);
VNarasimhaM
A: 

What is the C++ "correct" way of doing this const-to-nonconst? Static cast? Lexical cast? Something else?

There is no C++ way. For one reason or another, the author of that class decided that you should not be able to modify the instance through this method.

If you were the author, you could make it return a non-const reference. But those are still suspicious, unless the class really has no business hiding it from you (e.g like vector doesn't hide what it holds for you, and just hides how it holds stuff for you).

A better way (depending on what this is all about) might also be not to expose members for external manipulation, but rather provide a method that does this manipulation for you. For example:

class BadPosition
{
    int x, y;
 public:
    int& get_x() { return x; }
    int& get_y() { return x; }
    //...
};

BadPosition p;
p.get_x() += 1;
p.get_y() += -1;

class BetterPosition
{
    int x, y;
 public:
    void move(int x_inc, int y_inc) { x += x_inc; y += y_inc; }
    //...
};

BetterPosition p;
p.move(1, -1);

If you need this to put the class in a valid state later, then perhaps consider making its constructor do that. If you cannot do that, at least provide an Init() method, so as not to make such a complicated class rely entirely on being externally manipulated into something usable.

There may be of course other ways not requiring a cast, e.g you could create a copy, modify that, and then use the modified copy to replace the whole instance with another one (assuming this is enough to construct it):

X x;
...
Y y = x.get();
y.modify();
x = X(y);


Edit: So the class returns by value? In this case there should be no way to modify the instance in the class, since all you get is a copy in the first place. You can reference that with a const reference, but even if you cast away constness from that reference, you are still referencing a temporary.

My reply above assumed it returned a const reference, since that would seem a more sensible thing to do (I haven't seen people often return by const value, although probably there are those who strongly recommend it).

UncleBens
+5  A: 

I wouldn't use the const_cast solutions, and copying the object might not work. Instead, why not conditionally assign to another const reference? If myVar is valid, assign that. If not, assign the default. Then the code below can use this new const reference. One way to do this is to use the conditional expression:

const myType& myOtherVar = (myVar.isValid() ? myVar : defaultVar);

Another way is to write a function that takes a const reference (myVar) and returns either myVar or defaultVar, depending on the validity of myVar, and assign the return value from that to myOtherVar.

A third way is to use a const pointer, pointing it at either the address of myVar or the address of the default object.

swillden
Yay. This works.
V_D_R
+1  A: 

There's no "C++" way (not only to this, but to anything).

The bad way is to use a const_cast, but the behavior will then be undefined (read: don't do that).

What you should do is copy the object and then modify the copy. It's the only proper way to deal with immutable objects.

hasen j