C ++ 11 make_shared实例化 [英] C++11 make_shared instancing

查看:176
本文介绍了C ++ 11 make_shared实例化的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对长篇问题抱歉,但有些上下文是必要的。我有一些代码,似乎是一个有用的模式,我正在处理的项目:

  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);
}

...
}

正如你所看到的,它提供了一个简单的方法来构造任何类作为一个PointerType封装一个shared_ptr类型:

  auto oneFoo = Foo :: make(2); 

因此你可以得到shared_ptr的优点,而不必在代码库中引用make_shared和shared_ptr。



在类中封装智能指针类型具有以下几个优点:


  1. 让您控制指针类型的可复制性和可移动性。

  2. 隐藏调用者的shared_ptr详细信息,以便将非平凡对象构造(例如抛出异常的对象)放置在

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

  4. 它集中了关于(智能)指针构造和别名的细节

  5. 它可以让你决定哪些类可以使用智能指针,哪些类必须在栈上构造。 PointerType字段的存在向调用者提供关于可以创建对应于该类的什么类型的指针的提示。如果没有为类定义PointerType,这将指示不能创建指向该类的指针;因此,必须在堆栈上创建RAII类型的特定类。

但是,我看不到应用此位代码的明显方法到我的项目中的所有类,而不直接键入必需的typedef和static PointerType Instance()函数。我怀疑应该有一些一致的,C ++ 11标准,跨平台的方法这样做与基于策略的模板,但一些实验没有找到一个明显的方式应用这个trivially到一堆类在一个



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

解决方案

一种方法是使用好奇的循环模板模式

  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)...)
}
};

结构foo:public shared_factory< foo>
{
foo(char const *,int){}
};

我相信这会给你想要的。

  foo :: pointer_type f = foo :: make(hello,world,42); 



但是...



不推荐使用这种方法。尝试指示类型的用户如何实例化类型是不必要的限制。如果他们需要 std :: shared_ptr ,他们可以创建一个。如果他们需要一个 std :: unique_ptr ,他们可以创建一个。如果他们想在堆栈上创建一个对象,他们可以。



要解决您的问题:



  1. 它可以控制指针类型的可复制性和可移动性。


这是什么好处?



  1. 它隐藏调用者的shared_ptr详细信息,以便可以在Instance()调用中放置非平凡对象构造(例如抛出异常的构造)。


我不知道你的意思。希望不是你可以捕获异常并返回一个 nullptr



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


如果你使用多种智能指针,也许最好让用户为给定的情况选择适当的类型。此外,我认为使用相同的调用代码但返回不同类型的句柄可能会造成混淆。



  1. 它集中了关于(智能)指针构造和别名的细节,它们最了解如何做。


一个类在什么意义上知道如何做指针构建和别名的最?


< ol start =5>
  • 它允许您决定哪些类可以使用智能指针,哪些类必须在堆栈上构建。 PointerType字段的存在向调用者提供关于可以创建对应于该类的什么类型的指针的提示。如果没有为类定义PointerType,这将指示不能创建指向该类的指针;因此该特定类必须在堆栈上创建,RAII风格。


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


    Apologies for the long question, but some context is necessary. I have a bit of code that seems to be a useful pattern for the project I'm working on:

    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 );
        }
    
    ...
    }
    

    As you can see, it provides a straightforward way of constructing any class as a PointerType which encapsulates a shared_ptr to that type:

    auto oneFoo = Foo::make( 2 );
    

    And therefore you get the advantages of shared_ptr without putting references to make_shared and shared_ptr all over the code base.

    Encapsulating the smart pointer type within the class provides several advantages:

    1. It lets you control the copyability and moveability of the pointer types.
    2. It hides the shared_ptr details from callers, so that non-trivial object constructions, such as those that throw exceptions, can be placed within the Instance() call.
    3. You can change the underlying smart pointer type when you're working with projects that use multiple smart pointer implementations. You could switch to a unique_ptr or even to raw pointers for a particular class, and calling code would remain the same.
    4. It concentrates the details about (smart) pointer construction and aliasing within the class that knows most about how to do it.
    5. It lets you decide which classes can use smart pointers and which classes must be constructed on the stack. The existence of the PointerType field provides a hint to callers about what types of pointers can be created that correspond for the class. If there is no PointerType defined for a class, this would indicate that no pointers to that class may be created; therefore that particular class must be created on the stack, RAII style.

    However, I see no obvious way of applying this bit of code to all the classes in my project without typing the requisite typedef and static PointerType Instance() functions directly. I suspect there should be some consistent, C++11 standard, cross-platform way of doing this with policy-based templates, but a bit of experimentation has not turned up an obvious way of applying this trivially to a bunch of classes in a way that compiles cleanly on all modern C++ compilers.

    Can you think of an elegant way to add these concepts to a bunch of classes, without a great deal of cutting and pasting? An ideal solution would conceptually limit what types of pointers can be created for which types of classes (one class uses shared_ptr and another uses raw pointers), and it would also handle instancing of any supported type by its own preferred method. Such a solution might even handle and/or limit coercion, by failing appropriately at compile time, between non-standard and standard smart and dumb pointer types.

    解决方案

    One way is to use the curiously recurring template pattern.

    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) {}
    };
    

    I believe this gives you what you want.

    foo::pointer_type f = foo::make("hello, world", 42);
    

    However...

    I wouldn't recommend using this approach. Attempting to dictate how users of a type instantiate the type is unnecessarily restrictive. If they need a std::shared_ptr, they can create one. If they need a std::unique_ptr, they can create one. If they want to create an object on the stack, they can. I see nothing to be gained by mandating how your users' objects are created and managed.

    To address your points:

    1. It lets you control the copyability and moveability of the pointer types.

    Of what benefit is this?

    1. It hides the shared_ptr details from callers, so that non-trivial object constructions, such as those that throw exceptions, can be placed within the Instance() call.

    I'm not sure what you mean here. Hopefully not that you can catch the exception and return a nullptr. That would be Java-grade bad.

    1. You can change the underlying smart pointer type when you're working with projects that use multiple smart pointer implementations. You could switch to a unique_ptr or even to raw pointers for a particular class, and calling code would remain the same.

    If you are working with multiple kinds of smart pointer, perhaps it would be better to let the user choose the appropriate kind for a given situation. Besides, I'd argue that having the same calling code but returning different kinds of handle is potentially confusing.

    1. It concentrates the details about (smart) pointer construction and aliasing within the class that knows most about how to do it.

    In what sense does a class know "most" about how to do pointer construction and aliasing?

    1. It lets you decide which classes can use smart pointers and which classes must be constructed on the stack. The existence of the PointerType field provides a hint to callers about what types of pointers can be created that correspond for the class. If there is no PointerType defined for a class, this would indicate that no pointers to that class may be created; therefore that particular class must be created on the stack, RAII style.

    Again, I disagree fundamentally with the idea that objects of a certain type must be created and managed in a certain way. This is one of the reasons why the singleton pattern is so insidious.

    这篇关于C ++ 11 make_shared实例化的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆