Search code examples
c++slicevirtual-destructor

C++ slicing and virtual destructors


I get a vector of raw pointers, which I copy. The ownership of the objects pointed by these pointers belong to some other module. I have to replace some of the pointers with new ones which point to newly created objects. So in the end I will have a vector with pointers on which I need to call delete and others on which I do not. My idea was to introduce new classes which make this automatic.

template <typename T, class = std::enable_if_t<std::is_pointer<T>::value>>
class Pointer {
public:
    Pointer(T p) : pointer_(p) {}
    virtual ~Pointer() = default;

    T operator->()  { return pointer_; }

protected:
    T pointer_;
};

template <typename T>
class NotOwnedPointer : public Pointer<T> {
public:
    NotOwnedPointer(T p) : Pointer<T>(p) {}
    ~NotOwnedPointer() { std::cout << "not owned\n"; }
};

template <typename T>
class OwnedPointer : public Pointer<T> {
public:
    OwnedPointer(T p) : Pointer<T>(p) {}
    ~OwnedPointer() { std::cout << "owned\n"; delete this->pointer_; this->pointer_ = nullptr; }
    OwnedPointer(const OwnedPointer&) = delete;
    OwnedPointer& operator=(const OwnedPointer& other) = delete;
};

struct Foo {
    int i;
};

int main() {
    Foo* foo = new Foo{42};
    std::vector<Pointer<Foo*>> v;
    v.push_back(NotOwnedPointer(foo));
    v.push_back(OwnedPointer(foo));
}

Note that I use Pointer for the vector type instead of Pointer*. This way slicing will happen when I add a derived class instance to the vector.

Which destructors will be called when the vector is destructed? Since the type of the vector is Pointer I would say that the virtual table for class Pointer will be used and ~Pointer() will be called, but when I run the program it prints the text from ~NotOwnedPointer() and ~OwnedPointer().


Solution

  • v.push_back(NotOwnedPointer(foo));
    v.push_back(OwnedPointer(foo));
    

    These two lines create temporary objects (of type NotOwnedPointer and OwnedPointer, respectively), which are then sliced and copied into the vector.

    When the temporary objects are destroyed, their destructors are called (~NotOwnedPointer() and ~OwnedPointer(), respectively). This has nothing to do with v, which is destroyed later.