If I follow you correctly, you're looking for a clean way to have a private constructor that can only be invoked by std::make_shared or std::allocate_shared. Unfortunately this does not appear to be portable or easy, and I don't see a way to avoid your request to avoid friendship. However you can make the friend something that other people cannot easily co-opt. I'd call this mildly better, but it definitely has some downsides.
As this is not portable, the scenario I'm showing here is specific to the compiler I had handy: Visual Studio 2012. First I created a class like this:
class SomeClass
{
public:
int GetValue() const { return m_val; }
// optionally provide Ptr like yours?
// static std::shared_ptr<SomeClass> Ptr(int val) { return std::make_shared<SomeClass>(val); }
private:
SomeClass(int val) { m_val = val; }
SomeClass(const SomeClass&); // = delete;
SomeClass(SomeClass&&); // = delete;
~SomeClass() {}
int m_val;
};
This is enough to prevent usage like SomeClass thing(5);
Then I wanted to try to befriend std::make_shared. When I tried to compile code using this definition and std::make_shared<SomeClass>(5)
, I got an error pointing to what needed access:
error C2248 [...] cannot access private member [SomeClass::~SomeClass ...]
while compiling class template member function 'void std::_Ref_count_obj<_Ty>::_Destroy(void)'
After befriending class std::_Ref_count_obj<SomeClass>
(I first tried befriending the specific method, but that created worse problems), I also decided to fix the warning by befriending std::_Get_align<SomeClass>
:
warning C4624: 'std::_Get_align<_Ty [= SomeClass]>' : destructor could not be generated because a base class destructor is inaccessible
This left me with the following additions to this class that allows std::make_shared<SomeClass>(5)
but not SomeClass obj(5)
.
class SomeClass
{
: : :
// Allow use in VS2012 implementation of std::make_shared
friend class std::_Ref_count_obj<SomeClass>;
friend struct std::_Get_align<SomeClass>;
: : :
};
I'll leave other compilers up to you as you need them. It may be worth collecting a series of macro alternatives that you can put in any class that needs this capability.
SharedConstructable<T>
(more or less as given) and not expose a constructor? Or was that just an attempted means to accomplish another goal? \$\endgroup\$