factory, unique_ptr and static_cast
factory, unique_ptr and static_cast
考虑具有基对象、派生接口和最终对象的多态类:
// 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_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
};
}
static_move_cast
背后的目标是允许std::unique_ptr上的static_cast同时在强制转换期间移动删除器。代码是可以工作的,但是我想破解std::unique_ptr。是否有一种方法来重构代码以避免我的static_move_cast
?
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;
或者,更简单,直接构造并返回unique<object>
,因为T*
可以转换为object*
:
return unique<object>{
new T,
// ...
};
但是对于create_unique
,使用static_move_cast
是不可避免的,因为unique_ptr
的转换构造函数不能用于向下转换。
请注意,shared_ptr
有static_pointer_cast
,它执行向下强制转换,但unique_ptr
没有相应的工具,可能是因为它认为自己执行强制转换是直接和正确的。
考虑到需求,我认为这是一个很好的解决方案。您将责任转移给create_unique
的调用者。他必须给出正确的类型和字符串的组合以及注册表中的字符串。
auto instance = create_unique<interface1>("derived1");
// ^^^^^^^^^^ ^^^^^^^^
// what if those two don't match?
您可以通过将static_cast
更改为dynamic_cast
来改进它。create_unique
的调用者在调用它之前应该总是检查他得到了非空指针。
或者至少在调试模式下使用dynamic_cast
和assert
,这样可以在开发时捕获不匹配。
可选的重构:为每个现有的接口建立单独的工厂
- 如何理解C++标准N3337中的expr.const.cast子句8
- 为什么即使使用-cudart-static进行编译,库用户仍然需要链接到cuda运行时
- C++Cast运算符过载
- 如何处理 c++ 中类实现中的"invalid use of non-static data member"?
- 收到错误"invalid use of non-static data member 'stu::n' "
- LNK1104:无法打开libpjproject-i386-Win32-vc14-Debug-Static.lib
- 我应该在 C++ 中何时/为什么使用 STATIC?
- 在VS2019项目中集成ImageMagick:x64-windows-static library
- 如何处理Boost Spirit X3导致Visual Studio 2019 "static initialization order fiasco"?
- "static char __ = []() -> char"的含义
- 当初始值设定项是基类名时'initializer does not name a non-static data member or base class'错误
- 无法在 DLL 中链接 SDL2-static.lib
- 如何摆脱C++中未解析的外部符号"private: static char"错误?
- 错误:"cast"未命名类型void setCastDescription(std::string
- 通过使用 const-cast 的非常量引用来延长临时的寿命
- C++线程"Call to non-static member function without an object argument"
- 出现这种错误的原因是什么"invalid use of non-static data member "
- "(void) cast"与功能有什么区别 "__attributes__"来沉默未使用的参数警告?
- static是如何使用ClassA::m_variable处理所有类对象的
- 在[expr.static.cast]/4中,术语"一个可行函数"指的是什么