From your comments:
@Xeo, I understand what the rule of three is, the question is mostly
why is it a rule
Consider what happens here:
z& operator=( const z&ref )
{
hold = ref.hold;
return *this;
}
Lets say you have an instance of z
:
z myz;
myz.a.hold.push_back( new long_life );
...and then you create a copy of this myz
:
z my_other_z;
// ...
my_other_z = myz;
The operator=
implementation you have provided above simply copies the contents of the vector
. If the vector
has pointers, it doesn't make copies of whatever's being pointed to -- it just makes a literal copy of the pointer itself.
So after operator=
returns, you will have 2 instances of z
that have pointers pointing to the same thing. When the first of those z
s is destructed, it will delete the pointer:
~z(){ for( auto it=hold.begin();it!=hold.end() ++it ) delete(*it); };
When it comes time for the second z
to be destroyed, it will try to delete
the same pointer a second time. This results in Undefined Behavior.
The solution to this problem is to make deep copies when you assign or copy objects that maintain resources that need to be allocated and deleted. That means providing an assignment operator and a copy constructor.
That is why the rule of three is a RULE.
EDIT:
As others have mentioned, this is all better avoided altogether by using value semantics and RAII. Reengineering your objects to use the Rule of Zero, as others have called it, is a much better approach.