factory,unique_ptr和static_cast

was*_*ful 8 c++ c++11

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

// 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";
    }
};
Run Code Online (Sandbox Code Playgroud)

在实际用例中,最终对象是通过插件系统定义的,但这不是重点.请注意,我希望能够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;
}
Run Code Online (Sandbox Code Playgroud)

使用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)
            );
        }
    );
}
Run Code Online (Sandbox Code Playgroud)

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)
    );
}
Run Code Online (Sandbox Code Playgroud)

您注意到register_object并且create_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
    };
}
Run Code Online (Sandbox Code Playgroud)

背后的目标static_move_cast是在演员表中移动删除器时允许在std :: unique_ptr上使用static_cast.代码正在运行,但我觉得要乱砍std :: unique_ptr.有没有办法重构代码以避免我static_move_cast

eca*_*mur 1

static_move_cast在 中是不必要的register_object,因为您可以只使用 的转换构造函数unique_ptr template< class U, class E > unique_ptr( unique_ptr<U, E>&& u )

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

        return instance;
Run Code Online (Sandbox Code Playgroud)

或者,更简单的是,unique<object>直接构造并返回 a,因为T*可转换为object*

        return unique<object>{
            new T,
            // ...
        };
Run Code Online (Sandbox Code Playgroud)

然而, forcreate_unique的使用static_move_cast是不可避免的,因为 的转换构造函数unique_ptr不适用于向下转型。

请注意, shared_ptrhasstatic_pointer_cast执行向下转换,但没有相应的工具unique_ptr,大概是因为自己执行强制转换被认为是简单且正确的。