Search code examples
c++memorycopy-assignment

Implementing valuelike copy-assignment operator


In C++ Primer there is an example of using the copy-control members to make a class act "valuelike"; that is, when copying the object, the copies are independent. It proposes the following code:

class HasPtrValue
{
public:
    HasPtrValue(const std::string &s = std::string()) : ps(new std::string(s)), i(0) {  }
    HasPtrValue(const HasPtrValue &orig) : ps(new std::string(*orig.ps)), i(orig.i) { }
    HasPtrValue& operator=(const HasPtrValue&);
    ~HasPtrValue() { delete ps; };

    std::string *ps;
    int i;
};

HasPtrValue& HasPtrValue::operator=(const HasPtrValue &rhs)
{
    auto newp = new std::string(*rhs.ps);
    delete ps;
    ps = newp;
    i = rhs.i;
    return *this;
}

My question is regarding the copy-assignment operator. As I understand what it does is create a new string on the heap, delete the old one, and make the lhs point to the new one. Is that really necessary? Will the below code not do exactly the same thing by simply assigning to the existing string on the heap?

HasPtrValue& HasPtrValue::operator=(const HasPtrValue &rhs)
{
    *ps = *rhs.ps;
    i = rhs.i;
    return *this;
}

Solution

  • You are correct. Your version does not only work it is also more efficient since existing memory can be reused when ps->capacity() >= rhs.ps->capacity().

    If you want to provide strong exception guarantees you should use the copy-and-swap idiom:

    HasPtrValue& HasPtrValue::operator=(HasPtrValue copy) // notice the by value
    {
        swap(*this, copy);
        return *this;
    }
    
    // integrating tip from link posted by WhozCraig 
    friend void swap(HasPtrValue &lhs, HasPtrValue &rhs)
    {
        using std::swap;
        swap(lhs.ps, rhs.ps);
        swap(lhs.i, rhs.i);
    }
    

    Though your changes to the code should already provide the strong exception guarantee, as long as the assignment of i is not reordered by the compiler.