peterpi
peterpi

Reputation: 575

Is it acceptable to cast away constness in a move constructor?

Suppose I have a class Foo that has a private pointer to a Bar:

class Foo
{
private:
  Bar * bar;

public:
  Foo () : bar (new Bar ())
  {}

  ~Foo ()
  {
    delete bar;
  }
};

If the pointer bar should never be reassigned to a different instance, then it makes sense to make the pointer itself const in order to stop me (or a maintainer) from doing so in the future:

private:
  Bar * const bar;

I like doing this wherever the opportunity arises.

If I then wanted to write a move constructor, it would look something like this:

Foo (Foo && f) :
   bar (f.bar)
{
  f.bar = NULL;  // uh oh; f.bar is const.
}

I can "make the error go away" either by casting away the constness of f.bar or by not making it const in the first place. Neither of which are things I want to do. I'd rather not remove the const completely because it's there for a reason. On the other hand, casting away constness rings alarm bells for me and is something I never usually do. My question is: is it considered acceptable practice to cast away constness within a move constructor like this? Is there a better way that I haven't considered?

I don't think my question is the same as this one: Use const_cast to implement the move constructor

Upvotes: 8

Views: 500

Answers (3)

Anton Savin
Anton Savin

Reputation: 41331

If possible, use unique_ptr instead:

std::unique_ptr<Bar> bar;
Foo(Foo&& f) : bar(std::move(f.bar)){}
// or maybe you won't even have to declare move constructor

This way not only you'll get more safety and comfort, but also you won't accidentaly rewrite it with =, you'll have to call .reset() so you'll think twice before doing it (which is your aim, I suppose).

Upvotes: 3

SingerOfTheFall
SingerOfTheFall

Reputation: 29976

If you will have to change the pointer in some case (even if it's only a single case), then it probably shouldn't be const.

However, even putting this thought aside, using const_cast to remove constness from an object, and then using the result of the cast invokes undefined behavior. It is only safe to const_cast a variable that was originally not const.

Upvotes: 6

Yochai Timmer
Yochai Timmer

Reputation: 49261

You are basically contradicting yourself.
You are saying "I don't want to change it in any circumstance", and the you're saying "I want to change it when i move an object".

So, if there is a scenario where it needs to be changed, then it's not a const, and you can feel comfortable removing it.

If you are determined that you want it const, you can add another boolean value that determines ownership (if you need to handle resource life-time). So the pointed object may be released only when a destructor that owns the object is called.

Upvotes: 4

Related Questions