tenfour
tenfour

Reputation: 36896

Why is shared_ptr<void> not specialized?

shared_ptr<void> is special in that it, by definiton, will invoke undefined behavior by calling delete on a void*.

So, why is there not a shared_ptr<void> specialization which throws a compile error?

Upvotes: 6

Views: 1233

Answers (4)

Evan Teran
Evan Teran

Reputation: 90422

shared_ptr<T> is special in that it is by design allowed to hold a pointer to any pointer type which is convertible to T* and will use the proper deleter without UB! This comes into play with shared_ptr<Base> p(new Derived); scenarios, but also includes shared_ptr<void>.

For example:

#include <boost/shared_ptr.hpp>

struct T {
    T() { std::cout << "T()\n"; }
    ~T() { std::cout << "~T()\n"; }
};


int main() {
    boost::shared_ptr<void> sp(new T);
}

produces the output:

$ ./test
T()
~T()

If you visit http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/shared_ptr.htm, scroll down to the assignment section to see the very thing being demonstrated. See http://www.boost.org/doc/libs/1_47_0/libs/smart_ptr/sp_techniques.html#pvoid for more details.

EDIT as noted by trinithis, it is UB if the pointer type passed into the constructor is a void * pointer. Thanks for pointing that out!

Upvotes: 7

sehe
sehe

Reputation: 392931

Using shared_ptr to hold an arbitrary object

shared_ptr can act as a generic object pointer similar to void*. When a shared_ptr instance constructed as:

shared_ptr<void> pv(new X);

is destroyed, it will correctly dispose of the X object by executing ~X.

This propery can be used in much the same manner as a raw void* is used to temporarily strip type information from an object pointer. A shared_ptr can later be cast back to the correct type by using static_pointer_cast.

But how?

This constructor has been changed to a template in order to remember the actual pointer type passed. The destructor will call delete with the same pointer, complete with its original type, even when T does not have a virtual destructor, or is void

Upvotes: 8

Oliver Charlesworth
Oliver Charlesworth

Reputation: 272487

But it is valid, in many circumstances. Consider the following:

class T
{
public:
    ~T() { std::cout << "~T\n"; }
};

int main()
{
    boost::shared_ptr<void> sp(new T);
}

In circumstances where you try to pass a genuine void * into the shared_ptr constructor, you should get a compile error.

Upvotes: 1

Thomas Eding
Thomas Eding

Reputation: 1

If your pointer was created via something like malloc, you can make a shared_ptr<void, dtor>, where the dtor calls free. This will result in defined behavior.

But then again, perhaps you want undefined behavior :D

Upvotes: 4

Related Questions