仅通过基类"create"方法将对象创建为共享指针

Creating objects only as shared pointers through a base class 'create'-method

本文关键字:创建 对象 指针 共享 方法 基类 create      更新时间:2023-10-16

我正在努力实现应用程序中的某些对象只能通过调用名为"create"的静态方法构造为shared_ptr。

当然,我可以通过直接将静态"create"方法添加到所有相应的类中来实现这一点。然而,这意味着我必须在几乎所有的类中重复非常相似的代码。宏会起作用,但我觉得这不是很优雅。

我想出了一种替代方法,从实现"create"方法并返回指针的模板化"BaseObject"类派生所有类。除了std::make_shared在受保护时无法访问其子类的构造函数之外,这几乎是可行的。

非解决方案是公开子类构造函数(请参见下面示例中的(1))。但现在Foo可以正常地再次构建,这将破坏整个点。另一种解决方案是在子类中与BaseObject交朋友,并直接使用shared_ptr(请参见示例中的(2))。

这两种解决方案都给子类的实现者带来了额外的负担。因为他们必须找到一种使构造函数非公共的替代方法,或者放置一个友元声明。(2)解决方案还存在无法使用更高效的make_shared的问题。

我的问题是:有更好的方法吗?

template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(args...);
//return std::shared_ptr<T>(new T(args...)); (2)
}
};
class Foo : public BaseObject<Foo>
{
//friend BaseObject<Foo>; (2)
protected: //public (1)
Foo(int a = 0) : m_foo(a) {}
private:
int     m_foo;
};

int main(int argc, char* argv[])
{
Foo::SharedPtr bla = Foo::create(1);
return 0;
}

更新:

他们传递关键的习语似乎为我此刻提供了最好的解决方案:

template<class T>
class BaseObject
{
public:
typedef std::shared_ptr<T> SharedPtr;
class Key
{
friend class BaseObject<T>;
Key() {}
};
template<class... Args>
static typename BaseObject<T>::SharedPtr create(Args&&... args)
{
return std::make_shared<T>(Key(), args...);
}
};
class Foo : public BaseObject<Foo>
{
public:
Foo(BaseObject<Foo>::Key, int a = 0) : m_foo(a) {}
private:
int     m_foo;
};

好东西:

  • 只能通过创建Foo的对象作为shared_ptrFoo::创建
  • 无需在Foo中添加复杂的友元声明
  • std::make_shared仍然有效

此解决方案的唯一问题是要求将"Key"作为构造函数中的第一个参数。但我可以接受。

Better是主观的,但我相信如果您将构造函数设为私有函数,并将std::make_shared设为友元函数,会更直观一些。这样,唯一可以创建对象的函数将是std::make_shared,并且您可以编写

std::shared_ptr<Foo> ptr = std::make_shared<Foo>(12);

而不是:

Foo::SharedPtr bla = Foo::create(1);

因此,任何未来的代码读者都会理解您的意思,而无需实际查看Foo类。

更新

我试过我写的东西,但没有真正奏效。以下是一个类似问题的答案,很可能也适用于您的问题:

使用make_shared与受保护的构造函数+抽象接口

更新2

以下是如何使其工作(VC++2013)

#include <memory>
using namespace std;
class Foo
{
protected:
Foo(int a = 0) : m_foo(a) {}
private:
int     m_foo;
friend  shared_ptr<Foo> make_shared<>();
friend class _Ref_count_obj<Foo>;
};

int main()
{
shared_ptr<Foo> foo = make_shared<Foo, int>(12);
return 0;
}

_Ref_count_objmake_shared内部使用,这就是为什么你也需要与之成为朋友。