开发者

C++: how to deal with const object that needs to be modified?

开发者 https://www.devze.com 2022-12-08 20:01 出处:网络
I have a place in the code that used to say const myType & myVar = someMethod(); The problem is that:

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 mak开发者_开发知识库e myVar to be non-const.

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

    2. 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!


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.


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.


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).


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.


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


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); 


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).

0

精彩评论

暂无评论...
验证码 换一张
取 消