我有这样的代码,但我认为意图是明确的:

testmakeshared.cpp

#include <memory>

class A {
 public:
   static ::std::shared_ptr<A> create() {
      return ::std::make_shared<A>();
   }

 protected:
   A() {}
   A(const A &) = delete;
   const A &operator =(const A &) = delete;
};

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

但是当我编译它时,我得到了这个错误:

g++ -std=c++0x -march=native -mtune=native -O3 -Wall testmakeshared.cpp
In file included from /usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr.h:52:0,
                 from /usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/memory:86,
                 from testmakeshared.cpp:1:
testmakeshared.cpp: In constructor ‘std::_Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp>::_Sp_counted_ptr_inplace(_Alloc) [with _Tp = A, _Alloc = std::allocator<A>, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’:
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr_base.h:518:8:   instantiated from ‘std::__shared_count<_Lp>::__shared_count(std::_Sp_make_shared_tag, _Tp*, const _Alloc&, _Args&& ...) [with _Tp = A, _Alloc = std::allocator<A>, _Args = {}, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr_base.h:986:35:   instantiated from ‘std::__shared_ptr<_Tp, _Lp>::__shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>, _Args = {}, _Tp = A, __gnu_cxx::_Lock_policy _Lp = (__gnu_cxx::_Lock_policy)2u]’
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr.h:313:64:   instantiated from ‘std::shared_ptr<_Tp>::shared_ptr(std::_Sp_make_shared_tag, const _Alloc&, _Args&& ...) [with _Alloc = std::allocator<A>, _Args = {}, _Tp = A]’
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr.h:531:39:   instantiated from ‘std::shared_ptr<_Tp> std::allocate_shared(const _Alloc&, _Args&& ...) [with _Tp = A, _Alloc = std::allocator<A>, _Args = {}]’
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr.h:547:42:   instantiated from ‘std::shared_ptr<_Tp1> std::make_shared(_Args&& ...) [with _Tp = A, _Args = {}]’
testmakeshared.cpp:6:40:   instantiated from here
testmakeshared.cpp:10:8: error: ‘A::A()’ is protected
/usr/lib/gcc/x86_64-redhat-linux/4.6.1/../../../../include/c++/4.6.1/bits/shared_ptr_base.h:400:2: error: within this context

Compilation exited abnormally with code 1 at Tue Nov 15 07:32:58

这条消息基本上是在说模板实例化堆栈中::std::make_shared中的一些随机方法不能访问构造函数,因为它是受保护的。

但我真的想使用::std::make_shared和防止任何人创建这个类的对象不是由a::std::shared_ptr指向的。有什么办法可以做到吗?


当前回答

class A  {
public:
 static std::shared_ptr<A> getA() {
   std::shared_ptr<A> a = nullptr;
   a.reset(new A());
   return a;
 }

private:
  A() {}
};

由于std::make_shared不能调用私有构造函数,我们使用new手动创建A的实例。然后使用reset将shared_ptr设置为指向新的A对象。你不必担心泄露内存,shared_ptr会为你删除A。

其他回答

如果可能的话,你可以创建一个公共移动构造函数,如下所示:

class A {
 public:
   A(A&&) = default;
   static ::std::shared_ptr<A> create() {
      return ::std::make_shared<A>(std::move<A>(A{}));
   }

 protected:
   A() {}
   A(const A &) = delete;
   const A &operator =(const A &) = delete;
};

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

这可能是最简单的解决办法。基于Mohit Aron之前的回答,并结合dlf的建议。

#include <memory>

class A
{
public:
    static std::shared_ptr<A> create()
    {
        struct make_shared_enabler : public A {};

        return std::make_shared<make_shared_enabler>();
    }

private:
    A() {}  
};

当两个严格相关的类a和类B一起工作时,会出现一个更麻烦也更有趣的问题。

假设A是“主类”,B是“从类”。如果你想将B的实例化限制为A,你可以将B的构造函数设为private,并将B设为A的友例

class B
{
public:
    // B your methods...

private:
    B();
    friend class A;
};

不幸的是,从a的方法调用std::make_shared<B>()将使编译器抱怨B::B()是私有的。

我对此的解决方案是在B内部创建一个公共Pass虚拟类(就像nullptr_t一样),它有私有构造函数,与a是朋友,并使B的构造函数为公共,并将Pass添加到它的参数中,就像这样。

class B
{
public:
  class Pass
  {
    Pass() {}
    friend class A;
  };

  B(Pass, int someArgument)
  {
  }
};

class A
{
public:
  A()
  {
    // This is valid
    auto ptr = std::make_shared<B>(B::Pass(), 42);
  }
};

class C
{
public:
  C()
  {
    // This is not
    auto ptr = std::make_shared<B>(B::Pass(), 42);
  }
};
struct A {
public:
  template<typename ...Arg> std::shared_ptr<A> static create(Arg&&...arg) {
    struct EnableMakeShared : public A {
      EnableMakeShared(Arg&&...arg) :A(std::forward<Arg>(arg)...) {}
    };
    return std::make_shared<EnableMakeShared>(std::forward<Arg>(arg)...);
  }
  void dump() const {
    std::cout << a_ << std::endl;
  }
private:
  A(int a) : a_(a) {}
  A(int i, int j) : a_(i + j) {}
  A(std::string const& a) : a_(a.size()) {}
  int a_;
};

我意识到这个线程是相当旧的,但我找到了一个答案,不需要继承或额外的参数到构造函数,我不能在其他地方看到。但它是不可移植的:

#include <memory>

#if defined(__cplusplus) && __cplusplus >= 201103L
#define ALLOW_MAKE_SHARED(x) friend void __gnu_cxx::new_allocator<test>::construct<test>(test*);
#elif defined(_WIN32) || defined(WIN32)
#if defined(_MSC_VER) && _MSC_VER >= 1800
#define ALLOW_MAKE_SHARED(x) friend class std::_Ref_count_obj;
#else
#error msc version does not suport c++11
#endif
#else
#error implement for platform
#endif

class test {
    test() {}
    ALLOW_MAKE_SHARED(test);
public:
    static std::shared_ptr<test> create() { return std::make_shared<test>(); }

};
int main() {
    std::shared_ptr<test> t(test::create());
}

我已经在windows和linux上进行了测试,它可能需要针对不同的平台进行调整。