The problem is that data_
is deleted right after it is copied!
data_ = copy(r.data_);
delete data_; <<< PROBLEM
The best solution may be to employ copy-and-swap idiom (What is the copy-and-swap idiom?).
template <typename T>
Value<T>& Value<T>::operator=(const Value<T> rhs) // NOTE: pass by value
{
swap(data_, rhs.data_); // either std::swap or a custom swap,
// hard to say without knowing the type of data_
return *this;
}
Another alternative, a direct enhancement to OP's code, may be the following.
template <typename T>
Value<T>& Value<T>::operator=(const Value<T>& r)
{
// 1) Allocate new data. If, for some reason, the allocation throws,
// the original data_ stays intact. This offers better
// exception safety.
... new_data = ...;
// 2) Copy r.data to new_data (note: deep copy desired)
new_data = copy(r.data_);
// 3) Destroy original data_
delete data_;
// 4) Point data_ to new_data
data_ = new_data;
return *this;
}