Michał Górny
Michał Górny

Reputation: 19233

Is it a good idea to define partial copy with operator= (assignment)?

Please consider the following snippet:

class Pin
{
public:
    Pin()
    {
    }
};

class Connection
{
    Pin& _from;
    Pin& _to;

public:
    Connection(Pin& from, Pin& to)
        : _from(from), _to(to)
    {
    }
};

class Device
{
    Pin _a, _b;
    Connection _int_conn;

public:
    Device()
        : _int_conn(_a, _b)
    {
    }
};

Now I'd like to define operator= so that Device can be copied one to another:

int main()
{
    Device a, b;

    a = b;
}

Of course, the default operator= doesn't suffice because the Connection class holds two references. For this particular operation, it is however desirable that the Device copies all other properties and leaves the references intact (since they are expected to always point to the 'parent' pins).

On the other hand, the Connection class can be also used by user, and then the two pins can belong to any other class. In this case, although copying other properties may be beneficial, it seems a bit incorrect to use operator= for that. In other words:

int main()
{
    Pin a, b, c, d;
    Connection y(a, b), z(c, d);

    y = z;
}

to copy non-reference members seems wrong to me.

Moreover, if I ever decided to change references to pointers, I'd probably want operator= to copy them as well.

Am I right here? What is the best course of action? I think about defining an additional method like:

void Connection::copy_properties(Connection& rhs)

or just copying them in Device::operator=.

Upvotes: 0

Views: 157

Answers (1)

Luc Danton
Luc Danton

Reputation: 35449

[the references] are expected to always point to the 'parent' pins.

Is this an invariant of Connection or of Device? If the latter, consider this version of Connection:

class Connection
{
    Pin* _from;
    Pin* _to;

public:
    Connection(Pin& from, Pin& to)
        : _from(&from), _to(&to)
    {}
};

That is to say, this version has somewhat more obvious copy semantics. Then Device::operator= now has to make sure to not break the Device invariant (e.g. assign whatever needs assigning while leaving _int_conn unchanged). And in fact making _int_conn a const member can enforce that; but that's only as useful as the const interface of Connection.

Upvotes: 1

Related Questions