How to Call ::Std::Make_Shared on a Class With Only Protected or Private Constructors

How do I call ::std::make_shared on a class with only protected or private constructors?

This answer is probably better, and the one I'll likely accept. But I also came up with a method that's uglier, but does still let everything still be inline and doesn't require a derived class:

#include <memory>
#include <string>

class A {
protected:
struct this_is_private;

public:
explicit A(const this_is_private &) {}
A(const this_is_private &, ::std::string, int) {}

template <typename... T>
static ::std::shared_ptr<A> create(T &&...args) {
return ::std::make_shared<A>(this_is_private{0},
::std::forward<T>(args)...);
}

protected:
struct this_is_private {
explicit this_is_private(int) {}
};

A(const A &) = delete;
const A &operator =(const A &) = delete;
};

::std::shared_ptr<A> foo()
{
return A::create();
}

::std::shared_ptr<A> bar()
{
return A::create("George", 5);
}

::std::shared_ptr<A> errors()
{
::std::shared_ptr<A> retval;

// Each of these assignments to retval properly generates errors.
retval = A::create("George");
retval = new A(A::this_is_private{0});
return ::std::move(retval);
}

Edit 2017-01-06: I changed this to make it clear that this idea is clearly and simply extensible to constructors that take arguments because other people were providing answers along those lines and seemed confused about this.

Private constructor and make_shared

  1. As mentioned, std::make_shared or its component parts don't have access to private members.

  2. the call_once and once_flag are un-necessary. They are implicit in c++11 static initialisation,

  3. You normally would not want to expose the shared pointer.

 

class MyClass
{
MyClass() {}

public:
static MyClass& GetInstance()
{
static auto instance = MyClass();
return instance;
}
};

However, there is one case I can imagine where you would want to expose a shared pointer to the impl - this is in the case where the class can choose to 'break off' or 'reset' the impl to a new one. In this case I would consider code like this:

class MyClass2
{
MyClass2() {};

static auto& InternalGetInstance()
{
static std::shared_ptr<MyClass2> instance { new MyClass2 };
return instance;
}

public:

static std::shared_ptr<MyClass2> GetInstance()
{
return std::atomic_load(std::addressof(InternalGetInstance()));
}

static void reset() {
std::atomic_store(std::addressof(InternalGetInstance()),
std::shared_ptr<MyClass2>(new MyClass2));

}
};

However, in the end, it is my view that 'staticness' of a class should be an implementation detail, and unimportant to the user of the class:

#include <memory>
#include <utility>

class MyClass
{
// internal mechanics

struct Impl {

auto doSomething() {
// actual implementation here.
}
};

// getImpl now becomes the customisation point if you wish to change the
// bahviour of the class later
static Impl& getImpl() {
static auto impl = Impl();
return impl;
}


// use value semantics - it makes for more readable and loosely-coupled code
public:
MyClass() {}

// public methods defer to internal implementation

auto doSomething() {
return getImpl().doSomething();
}
};


int main() {

// note: just create objects
auto mc = MyClass();
mc.doSomething();

// now we can pass the singleton as an object. Other functions don't even
// need to know it's a singlton:

extern void somethingElse(MyClass mc);
somethingElse(mc);
}

void somethingElse(MyClass mc)
{

}

Access private constructor from public static member function using shared_ptr in C++ [duplicate]

class A {
private:
A() {}

public:
static std::shared_ptr<A> make() {
return std::shared_ptr<A>(new A());
}
};

Passkey idiom with std::make_shared. xmemory cannot access private Key constructor

The problem is that the compiler needs to copy your Widget::Key when you call std::make_shared, and you have declared the copy constructor private. You can solve this in one of two ways:

  1. Make the copy constructor of Widget::Key public.

  2. Change the Widget constructor to take the Widget::Key by const reference:

    explicit Widget(const Key&, ...

Using make_shared with a protected constructor + abstract interface

With VC10 the solution you linked to doesn't work - the construction of the instance of InterfaceImpl doesn't happen in make_shared, but in an internal type in std::tr1::_Ref_count_obj<Ty>::_Ref_count_obj(void).

I'd just make the Create() function a friend in your case and not use make_shared():

class InterfaceImpl : public IInterface {
// ...
protected:
friend std::shared_ptr<IInterface> Create();
InterfaceImpl() {}
};

std::shared_ptr<IInterface> Create() {
return std::shared_ptr<IInterface>(new InterfaceImpl());
}

... or use a custom make_shared() implementation that you actually can befriend without relying on ugly implementation details.

An alternative would be to use something like this pass-key-idiom:

class InterfaceImpl : public IInterface {
public:
class Key {
friend std::shared_ptr<IInterface> Create();
Key() {}
};
InterfaceImpl(const Key&) {}
};

std::shared_ptr<IInterface> Create() {
std::shared_ptr<IInterface> object =
std::make_shared<InterfaceImpl>(InterfaceImpl::Key());
return object;
}

Force the users to create an new instance by call a method which returns a shared_ptr of the class itself [duplicate]

You can make the shared yourself. Will this work for you?

#include <iostream>
#include <memory>

class Foo : public std::enable_shared_from_this<Foo> {
private: //the user should construct an instance through the constructor below.
Foo(int num):num_(num) { std::cout << "Foo::Foo\n"; }
public:
~Foo() { std::cout << "Foo::~Foo\n"; }
static std::shared_ptr<Foo> Create() {
Foo *foo = new Foo(5);
return std::shared_ptr<Foo>(foo);
}
private:
int num_;
};

int main() {
auto pf = Foo::Create();
}


Related Topics



Leave a reply



Submit