I have this code that doesn\'t work, but I think the intent is clear:
testmakeshared.cpp
#include
class A {
public:
stat
Since I didn't like the already provided answers I decided to search on and found a solution that is not as generic as the previous answers but I like it better(tm). In retrospect it is not much nicer than the one provided by Omnifarius but there could be other people who like it too :)
This is not invented by me, but it is the idea of Jonathan Wakely (GCC developer).
Unfortunately it does not work with all the compilers because it relies on a small change in std::allocate_shared implementation. But this change is now a proposed update for the standard libraries, so it might get supported by all the compilers in the future. It works on GCC 4.7.
C++ standard Library Working Group change request is here: http://lwg.github.com/issues/lwg-active.html#2070
The GCC patch with an example usage is here: http://old.nabble.com/Re%3A--v3--Implement-pointer_traits-and-allocator_traits-p31723738.html
The solution works on the idea to use std::allocate_shared (instead of std::make_shared) with a custom allocator that is declared friend to the class with the private constructor.
The example from the OP would look like this:
#include
template
struct MyAlloc : std::allocator
{
void construct(void* p) { ::new(p) Private(); }
};
class A {
public:
static ::std::shared_ptr create() {
return ::std::allocate_shared(MyAlloc());
}
protected:
A() {}
A(const A &) = delete;
const A &operator =(const A &) = delete;
friend struct MyAlloc;
};
int main() {
auto p = A::create();
return 0;
}
A more complex example that is based on the utility I'm working on. With this I could not use Luc's solution. But the one by Omnifarius could be adapted. Not that while in the previous example everybody can create an A object using the MyAlloc in this one there is not way to create A or B besides the create() method.
#include
template
class safe_enable_shared_from_this : public std::enable_shared_from_this
{
public:
template
static ::std::shared_ptr create(_Args&&... p_args) {
return ::std::allocate_shared(Alloc(), std::forward<_Args>(p_args)...);
}
protected:
struct Alloc : std::allocator
{
template
void construct(_Up* __p, _Args&&... __args)
{ ::new((void *)__p) _Up(std::forward<_Args>(__args)...); }
};
safe_enable_shared_from_this(const safe_enable_shared_from_this&) = delete;
safe_enable_shared_from_this& operator=(const safe_enable_shared_from_this&) = delete;
};
class A : public safe_enable_shared_from_this {
private:
A() {}
friend struct safe_enable_shared_from_this::Alloc;
};
class B : public safe_enable_shared_from_this {
private:
B(int v) {}
friend struct safe_enable_shared_from_this::Alloc;
};
int main() {
auto a = A::create();
auto b = B::create(5);
return 0;
}