Question

I've been working on a way to prevent user of using a class without smart pointers. Thus, forcing them to have the object being heap allocated and managed by smart pointers. In order to get such a result, I've tried the following :

#include <memory>
class A
{
private :
    ~A {}
    // To force use of A only with std::unique_ptr
    friend std::default_delete<A>;
};

This work pretty well if you only want your class users being capable of manipulating instance of your class through std::unique_ptr. But it doesn't work for std::shared_ptr. So I'd like to know if you had any ideas to get such a behavior. The only solution that I've found is doing the following (using friend std::allocator_traits<A>; was unsufficient) :

#include <memory>
class A
{
private :
    ~A {}
    // For std::shared_ptr use with g++
    friend __gnu_cxx::new_allocator<A>;
};

But this solution is not portable. Maybe I'm doing it the wrong way.

Was it helpful?

Solution

Create a friend'd factory function that returns a std::unique_ptr<A>, and make your class have no accessible constructors. But make the destructor available:

#include <memory>

class A;

template <class ...Args>
std::unique_ptr<A> make_A(Args&& ...args);

class A
{
public:
    ~A() = default;
private :
    A() = default;
    A(const A&) = delete;
    A& operator=(const A&) = delete;

    template <class ...Args>
    friend std::unique_ptr<A> make_A(Args&& ...args)
    {
        return std::unique_ptr<A>(new A(std::forward<Args>(args)...));
    }
};

Now your clients can obviously get a unique_ptr<A>:

std::unique_ptr<A> p1 = make_A();

But your clients can just as easily get a shared_ptr<A>:

std::shared_ptr<A> p2 = make_A();

Because std::shared_ptr can be constructed from a std::unique_ptr. And if you have any user-written smart pointers, all they have to do to be interoperable with your system is create a constructor that takes a std::unique_ptr, just like std::shared_ptr has, and this is very easy to do:

template <class T>
class my_smart_ptr
{
    T* ptr_;
public:
    my_smart_ptr(std::unique_ptr<T> p)
        : ptr_(p.release())
    {
    }
    // ...
};

OTHER TIPS

As there is no general term "smart pointer" what you want is not possible.

What you can do, is supporting some known set of smart pointers. The usual solution starts as yours, making ctor or dtor private, and adds factory functions. That can return the instance packed with your desired smart pointers. If you just want to support unique_ptr and shared_ptr, that meaans two factory functions, hardly too much. (note that those pointers allow smuggling out the raw pointer through simple interface so the control is not full.)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top