English 中文(简体)
Member assignment in a const function
原标题:

I have a class member myMember that is a myType pointer. I want to assign this member in a function that is declared as const. I m doing as follows:

void func() const
{
     ...
     const_cast<myType*>(myMember) = new myType();
     ...
}

Doing this works fine in VC++, but GCC gives an error with the message "lvalue required as left operand of assignment".

Making the member mutable allow me to simply remove the const_cast and assign the value. However, I m not entirely sure that that comes with other side-effects.

Can I assign my member without having to make the member mutable? How? Are there any side-effects in making members mutable?

最佳回答

The code wont actually work in VC++ - you re not updating the value (or at least it shouldnt), hence the warning from GCC. Correct code is

const_cast<myType*&>(myMember) = new myType();

or [from other response, thanks :P]:

const_cast<ThisType*>(this)->myMember = new myType();

Making it mutable effectively means you get implicit const_casts in const member functions, which is generally what you should be steering towards when you find yourself doing loads of const_casts on this. There are no side-effects to using mutable other than that.

As you can see from the vehement debates circling this question, willy-nilly usage of mutable and lots of const_casts can definitely be symptoms of bad smells in your code. From a conceptual point of view, casting away constness or using mutable can have much larger implications. In some cases, the correct thing to do may be to change the method to non-const, i.e., own up to the fact that it is modifying state.

It all depends on how much const-correctness matters in your context - you dont want to end up just sprinking mutable around like pixie dust to make stuff work, but mutable is intended for usage if the member isnt part of the observable state of the object. The most stringent view of const-correctness would hold that not a single bit of the object s state can be modified (e.g., this might be critical if you re instance is in ROM...) - in those cases you dont want any constness to be lost. In other cases, you might have some external state stored somewhere ouside of the object - e.g., a thread-specific cache which also needs to be considered when deciding if it is appropriate.

问题回答

This scenario -- an encapsulated internal state change that does not impact external state (e.g. caching results) -- is exactly what the mutable keyword is for.

const_cast is nearly always a sign of design failure. In your example, either func() should not be const, or myMember should be mutable.

A caller of func() will expect her object not to change; but this means "not to change in a way she can notice"; this is, not to change its external state. If changing myMember does not change the object external state, that is what the mutable keyword is for; otherwise, func() should not be const, because you would be betraying your function guarantees.

Remember that mutable is not a mechanism to circunvent const-correctness; it is a mechanism to improve it.

class Class{
int value;
void func()const{
const_cast<Class*>(this)->value=123;
}
};

As Steve Gilham wrote, mutable is the correct (and short) answer to your question. I just want to give you a hint in a different direction. Maybe it s possible in your szenario to make use of an (or more than one) interface? Perhaps you can grok it from the following example:

class IRestrictedWriter // may change only some members
{
public:
  virtual void func() = 0; 
}

class MyClass : virtual public IRestrictedWriter
{
public:
  virtual void func()
  {
    mValueToBeWrittenFromEverybody = 123; 
  }

  void otherFunctionNotAccessibleViaIRestrictedWriter()
  {
    mOtherValue1 = 123;
    mOtherValue2 = 345;
  }

  ...   
}

So, if you pass to some function an IRestrictedReader * instead of a const MyClass * it can call func and thus change mValueToBeWrittenFromEverybody whereas mOtherValue1 is kind of "const".

. I find mutable always a bit of a hack (but use it sometimes).





相关问题
Undefined reference

I m getting this linker error. I know a way around it, but it s bugging me because another part of the project s linking fine and it s designed almost identically. First, I have namespace LCD. Then I ...

C++ Equivalent of Tidy

Is there an equivalent to tidy for HTML code for C++? I have searched on the internet, but I find nothing but C++ wrappers for tidy, etc... I think the keyword tidy is what has me hung up. I am ...

Template Classes in C++ ... a required skill set?

I m new to C++ and am wondering how much time I should invest in learning how to implement template classes. Are they widely used in industry, or is this something I should move through quickly?

Print possible strings created from a Number

Given a 10 digit Telephone Number, we have to print all possible strings created from that. The mapping of the numbers is the one as exactly on a phone s keypad. i.e. for 1,0-> No Letter for 2->...

typedef ing STL wstring

Why is it when i do the following i get errors when relating to with wchar_t? namespace Foo { typedef std::wstring String; } Now i declare all my strings as Foo::String through out the program, ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

Window iconification status via Xlib

Is it possible to check with the means of pure X11/Xlib only whether the given window is iconified/minimized, and, if it is, how?

热门标签