C++ 11 make_shared实例化

joh*_*yrd 7 c++ templates smart-pointers shared-ptr c++11

为长期问题道歉,但有些背景是必要的.我有一些代码似乎是我正在进行的项目的有用模式:

class Foo
{
public:
    Foo( int bar = 1 );
    ~Foo();
    typedef std::shared_ptr< Foo > pointer_type;
    static pointer_type make( int bar = 1 )
    {
        return std::make_shared< Foo >( bar );
    }

...
}
Run Code Online (Sandbox Code Playgroud)

如您所见,它提供了一种将任何类构造为PointerType的简单方法,该类将shared_ptr封装到该类型:

auto oneFoo = Foo::make( 2 );
Run Code Online (Sandbox Code Playgroud)

因此,您可以获得shared_ptr的优势,而无需在整个代码库中引用make_shared和shared_ptr.

在类中封装智能指针类型提供了几个优点:

  1. 它允许您控制指针类型的可复制性和可移动性.
  2. 它隐藏了调用者的shared_ptr细节,因此可以将非平凡的对象构造(例如抛出异常的构造)置于Instance()调用中.
  3. 在使用多个智能指针实现的项目时,可以更改基础智能指针类型.您可以切换到unique_ptr甚至是特定类的原始指针,并且调用代码将保持不变.
  4. 它集中了关于(智能)指针构造和别名的细节,这些关于最了解如何操作的类.
  5. 它允许您决定哪些类可以使用智能指针以及哪些类必须在堆栈上构建.PointerType字段的存在向调用者提供了关于可以为类创建哪些类型的指针的提示.如果没有为类定义PointerType,这将表明不能创建指向该类的指针; 因此,必须在堆栈上创建特定的类,RAII样式.

但是,我没有看到将这段代码应用于项目中的所有类的明显方法,而无需直接键入必需的typedef和静态PointerType Instance()函数.我怀疑应该有一些一致的,C++ 11标准,跨平台的方式来实现这一点与基于策略的模板,但一些实验并没有显示出一种明显的方式将这个简单地应用于一堆类中的一个在所有现代C++编译器上完全编译的方式.

你能想到一种优雅的方式将这些概念添加到一堆类中,而不需要大量的剪切和粘贴吗?理想的解决方案是概念性地限制可以为哪些类型的类创建哪些类型的指针(一个类使用shared_ptr而另一个类使用原始指针),并且它还将通过其自己的首选方法处理任何受支持类型的实例化.这种解决方案甚至可以通过在编译时适当地在非标准和标准智能和哑指针类型之间失败来处理和/或限制强制.

Jos*_*son 10

一种方法是使用奇怪的重复模板模式.

template<typename T>
struct shared_factory
{
    using pointer_type = std::shared_ptr<T>;

    template<typename... Args>
    static pointer_type make(Args&&... args)
    {
        return std::make_shared<T>(std::forward<Args>(args)...);
    }
};

struct foo : public shared_factory<foo>
{
    foo(char const*, int) {}
};
Run Code Online (Sandbox Code Playgroud)

我相信这会给你你想要的东西.

foo::pointer_type f = foo::make("hello, world", 42);
Run Code Online (Sandbox Code Playgroud)

然而...

我不建议使用这种方法.试图规定类型的用户如何实例化该类型是不必要的限制.如果他们需要std::shared_ptr,他们可以创建一个.如果他们需要std::unique_ptr,他们可以创建一个.如果他们想在堆栈上创建一个对象,他们可以.通过强制创建和管理用户对象的方式,我看不到任何好处.

为了解决你的观点:

  1. 它允许您控制指针类型的可复制性和可移动性.

这有什么好处?

  1. 它隐藏了调用者的shared_ptr细节,因此可以将非平凡的对象构造(例如抛出异常的构造)置于Instance()调用中.

我不确定你的意思.希望不是你可以捕获异常并返回一个nullptr.这将是Java级别的糟糕.

  1. 在使用多个智能指针实现的项目时,可以更改基础智能指针类型.您可以切换到unique_ptr甚至是特定类的原始指针,并且调用代码将保持不变.

如果您正在使用多种智能指针,那么让用户为给定情况选择合适的类型可能会更好.此外,我认为拥有相同的调用代码但返回不同类型的句柄可能会造成混淆.

  1. 它集中了关于(智能)指针构造和别名的细节,这些关于最了解如何操作的类.

在什么意义上,一个类对于如何进行指针构造和别名最"知道"?

  1. 它允许您决定哪些类可以使用智能指针以及哪些类必须在堆栈上构建.PointerType字段的存在向调用者提供了关于可以为类创建哪些类型的指针的提示.如果没有为类定义PointerType,这将表明不能创建指向该类的指针; 因此,必须在堆栈上创建特定的类,RAII样式.

同样,我基本上不同意必须以某种方式创建和管理某种类型的对象的想法.这是单身模式如此阴险的原因之一.


Rob*_*b L 2

我不建议添加这些静态函数。除了其他缺点之外,当存在多个构造函数时,它们的创建和维护确实变得相当繁重。在这种情况下,auto 以及类外的 typedef 都可以提供帮助。另外,您可以使用 std 命名空间(但请不要在标头中):

class Foo
{
public:
    Foo();
    ~Foo();
    Foo( int bar = 1 );

...
}

typedef std::shared_ptr<Foo> FooPtr;
Run Code Online (Sandbox Code Playgroud)

在 C++ 文件中:

using namespace std;
auto oneFoo = make_shared<Foo>( 2 );
FooPtr anotherFoo = make_shared<Foo>( 2 );
Run Code Online (Sandbox Code Playgroud)

我想您会发现这对于打字来说并不算太麻烦。当然,这都是风格问题。