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
As mentioned,
std::make_shared
or its component parts don't have access to private members.the
call_once
andonce_flag
are un-necessary. They are implicit in c++11 static initialisation,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:
Make the copy constructor of
Widget::Key
public.Change the
Widget
constructor to take theWidget::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
Why Would We Call Cin.Clear() and Cin.Ignore() After Reading Input
Does "Undefined Behavior" Really Permit *Anything* to Happen
Variable Number of Arguments in C++
How to Stop C++ Console Application from Exiting Immediately
How to Convert Between Big-Endian and Little-Endian Values in C++
Difference Between G++ and Gcc
Why Do Function Pointer Definitions Work With Any Number of Ampersands '&' or Asterisks '*'
Using Getline(Cin, S) After Cin
Why Should I Use a Pointer Rather Than the Object Itself
Cin and Getline Skipping Input
How to Convert an Instance of Std::String to Lower Case
What Exactly Is a Type Cast in C/C++
How to Properly Clean Up Elements from Vectors of Object Pointers
Define Preprocessor Macro Through Cmake
Undefined Behavior and Sequence Points
When and Why Will a Compiler Initialise Memory to 0Xcd, 0Xdd, etc. on Malloc/Free/New/Delete