Lets say we have the following class:
class Foo
{
public:
Foo() { _bar=new Bar };
Foo(const Foo &right) { _bar=new Bar(right.bar); };
Foo(Foo &&right) { _bar=right._bar; right.bar=new Bar(); };
~Foo() { delete _bar; }
Foo &operator=(const Foo &right) { _bar->opertor=(right.bar); return *this;}
Foo &operator=(Foo &&right) { std::swap(_bar, right._bar); return *this;}
void func() { _bar->test=1 };
private:
Bar *_bar;
};
is it legitimate to alter it to the following and expect the end user to know that after the move is performed that the rvalue is no longer valid (in that calling anything other than the assignment operator could crash)?
class Foo
{
public:
Foo() { _bar=new Bar };
Foo(const Foo &right) { _bar=new Bar(right.bar); };
Foo(Foo &&right) { _bar=right._bar; right.bar=nullptr; };
~Foo() { if(_bar != nullptr) delete _bar; }
Foo &operator=(const Foo &right)
{
if(_bar == nullptr)
_bar=new Bar();
_bar->opertor=(right.bar);
return *this;
}
Foo &operator=(Foo &&right)
{
if(_bar != nullptr)
delete _bar;
_bar=right._bar;
right._bar=nullptr;
return *this;
}
void func() { _bar->test=1 };
private:
Bar *_bar;
};
my concern comes from the fact that func (and all other functions in the class) assume that _bar exists.
In principle it may become invalid, though you might want consider leaving it in an assignable state (which your original implementation, hence edited, did not do). This would follow the policy of the standard library, which says:
Unless otherwise specified, all standard library objects that have been moved from are placed in a valid but unspecified state. That is, only the functions without preconditions, such as the assignment operator, can be safely used on the object after it was moved from
I'd recommend reimplementing the assignment operator such that it swaps "this" object with a newly constructed one. This is generally a good way to avoid introducing incorrect behaviour when implementing assignments.
A moved-from object is supposed to be in a valid but unspecified state. Note that this is a recommendation but not an absolute requirement of the standard.
Your second code will break if a normal operation is performed on it afterwards (specifically, the copy-assignment operator).
If _bar == nullptr is a valid state then your copy-assignment operator is bugged; if it is not a valid state then I would say your move-constructor is bugged.
NB. In the second code, the if check in the destructor is redundant, as it is legal to delete a null pointer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With