【问题标题】:factory, unique_ptr and static_cast工厂、unique_ptr 和 static_cast
【发布时间】:2017-01-12 20:41:00
【问题描述】:

考虑具有基对象、派生接口和最终对象的多态类:

// base object

struct object
{
    virtual ~object() = default;
};

// interfaces derived from base object

struct interface1 : object
{
    virtual void print_hello() const = 0;

    template<typename T>
    static void on_destruction(object* /*ptr*/)
    {
        std::cout << "interface1::on_destruction" << std::endl;
    }
};

// final object

struct derived1 : interface1
{
    virtual void print_hello() const override
    {
        std::cout << "hello" << std::endl;
    }

    static std::string get_type_name()
    {
        return "derived1";
    }
};

在实际用例中,最终对象是通过插件系统定义的,但这不是重点。请注意,我希望能够在对象被销毁时调用on_destruction(参见下面的register_object)。我想按如下方式使用这些类:

int main()
{
    // register derived1 as an instantiable object,
    // may be called in a plugin

    register_object<derived1>();

    // create an instance using the factory system

    auto instance = create_unique<interface1>("derived1");
    instance->print_hello();

    return 0;
}

使用 std::unique_ptr 管理对象,我最终得到了register_object 的以下代码:

template<typename T>
using unique = std::unique_ptr<
    T,
    std::function<void(object*)> // object deleter
>;

namespace
{
    std::map< std::string, std::function<unique<object>(void)> > factory_map;
}

template<typename T>
void register_object()
{
    factory_map.emplace(
        T::get_type_name(),
        []()
        {
            unique<T> instance{
                new T,
                [](object* ptr)
                {
                    T::on_destruction<T>(ptr);

                    delete ptr;
                }
            };

            return static_move_cast<object>(
                std::move(instance)
            );
        }
    );
}

还有create* 函数:

unique<object> create_unique_object(const std::string& type_name)
{
    auto f = factory_map.at(type_name);
    return f();
}

template<typename T>
unique<T> create_unique(const std::string& type_name)
{
    return static_move_cast<T>(
        create_unique_object(type_name)
    );
}

您注意到在register_objectcreate_unique 中对static_move_cast 的调用被声明为:

template<typename U, typename T, typename D>
std::unique_ptr<U, D>
static_move_cast
(
    std::unique_ptr<T, D>&& to_move_cast
)
{
    auto deleter = to_move_cast.get_deleter();

    return std::unique_ptr<U, D>{
        static_cast<U*>(
            to_move_cast.release()
        ),
        deleter
    };
}

static_move_cast 背后的目标是允许在 std::unique_ptr 上进行 static_cast,同时在转换期间移动删除器。代码正在运行,但我觉得要破解 std::unique_ptr。有没有办法重构代码以避免我的static_move_cast

【问题讨论】:

  • Ew, object 基地
  • 如果您希望在其他地方重用您的static_move_cast,您可能需要为使用std::default_delete&lt;T&gt; 的情况添加一个单独的模板函数(您现在使用的版本将适用于它们,但将产生一个不合需要类型的对象 - std::unique_ptr 将被转换为 std::unique_ptr> 这真的很尴尬)。 Here你可以找到我不久前为自己写的版本

标签: c++ c++11


【解决方案1】:

static_move_castregister_object 中是不必要的,因为您可以只使用converting constructor of unique_ptr template&lt; class U, class E &gt; unique_ptr( unique_ptr&lt;U, E&gt;&amp;&amp; u )

        unique<T> instance{
            new T,
            // ...
        };

        return instance;

或者,甚至更简单,直接构造并返回一个unique&lt;object&gt;,因为T* 可以转换为object*

        return unique<object>{
            new T,
            // ...
        };

但是对于create_unique,使用static_move_cast 是不可避免的,因为unique_ptr 的转换构造函数不适用于向下转换。

请注意shared_ptrstatic_pointer_cast,它执行向下转换,但unique_ptr 没有相应的设施,大概是因为它被认为是直接和正确的自己执行转换。

【讨论】:

    【解决方案2】:

    考虑到要求,我会说这是一个很好的解决方案。您将责任转移给create_unique 的调用者。他必须给出正确的类型和字符串组合以及注册表中的字符串。

    auto instance = create_unique<interface1>("derived1");
    //                            ^^^^^^^^^^   ^^^^^^^^
    //                         what if those two don't match?
    

    您可以通过将static_cast 更改为dynamic_cast 来改进它。 create_unique 的调用者应该在调用任何东西之前检查他是否得到了非空指针。

    或者至少在调试模式下使用dynamic_castassert,这样你在开发时就会发现不匹配。


    替代性重构:为每个现有接口设置单独的工厂。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-01
      • 2011-01-05
      • 2020-03-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多