Question

I would like to define a shared pointer whose operator== compares the pointed to values instead of the pointers, something like this:

template <typename T>
struct deref_shared_ptr: std::shared_ptr<T> {
    bool operator==(const deref_shared_ptr rhs) const { 
        return (**this == *rhs);
    }
};

This type has two potential problems:

  • It derives from a standard library type.

  • It violates the Liskov substitution principle, since it changes the semantics of operator==.

However, I am thinking that neither of the two is a problem unless one uses the base type pointer/reference to refer to the derived type. In particular, these problems might never occur in template code. For shared pointers the situation is even better: shared pointers are stored and passed by value.

Is my logic correct? Are there still good reasons to avoid the above definition in favor of composition?

Was it helpful?

Solution

I won't say your logic is definitively wrong, but it gives me a queasy feeling -- e.g. what happens if someone accidentally uses it as a shared_ptr anyway?

In this sort of situation I make my own class that contains the shared_ptr. E.g.

class CustomPtr {
    shared_ptr<XType> m_xp;
public:
    ... some stuff ....
    operator bool()const{return (bool)m_xp;}
    void reset() {m_xp.reset();}

    Transport *operator->(){return m_xp.get();}
    const Transport *operator->()const{return m_xp.get();}
    ... more stuff ....
};

I have to proxy or otherwise wrap any interface that I want to use -- but I consider this an advantage. I generally only use a handful of access methods, and I like to be confident that no-one is using unexpected methods.

Licensed under: CC-BY-SA with attribution
scroll top