Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/159.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ &引用;“向下投射”;独特的_ptr<;基地>;至唯一的\u ptr<;派生>;_C++_C++11_Smart Pointers_Factory Pattern_Unique Ptr - Fatal编程技术网

C++ &引用;“向下投射”;独特的_ptr<;基地>;至唯一的\u ptr<;派生>;

C++ &引用;“向下投射”;独特的_ptr<;基地>;至唯一的\u ptr<;派生>;,c++,c++11,smart-pointers,factory-pattern,unique-ptr,C++,C++11,Smart Pointers,Factory Pattern,Unique Ptr,我有一系列工厂返回unique\u ptr。不过,在引擎盖下,它们提供指向各种派生类型的指针,即unique\u ptr、unique\u ptr、unique\u ptr等 给定DerivedA:Derived和Derived:Base我们有: unique_ptr<Base> DerivedAFactory() { return unique_ptr<Base>(new DerivedA); } 这是有效的,还是会有什么奇怪的事情发生 另外,还有一个更复杂

我有一系列工厂返回
unique\u ptr
。不过,在引擎盖下,它们提供指向各种派生类型的指针,即
unique\u ptr
unique\u ptr
unique\u ptr

给定
DerivedA:Derived
Derived:Base
我们有:

unique_ptr<Base> DerivedAFactory() {
    return unique_ptr<Base>(new DerivedA);
}
这是有效的,还是会有什么奇怪的事情发生



另外,还有一个更复杂的问题,一些工厂驻留在运行时动态加载的DLL中,这意味着我需要确保生成的对象在创建时在相同的上下文(堆空间)中被销毁。所有权的转移(通常发生在另一个上下文中)必须从原始上下文中提供一个deleter。但是除了必须随指针一起提供/强制转换一个deleter之外,强制转换的问题应该是相同的。

我将创建两个函数模板,
静态的\u惟一的\u ptr\u强制转换
动态的\u惟一的\u ptr\u强制转换
。如果绝对确定指针实际上是派生的*,则使用前者,否则使用后者

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
static_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    auto d = static_cast<Derived *>(p.release());
    return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
}

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
dynamic_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    if(Derived *result = dynamic_cast<Derived *>(p.get())) {
        p.release();
        return std::unique_ptr<Derived, Del>(result, std::move(p.get_deleter()));
    }
    return std::unique_ptr<Derived, Del>(nullptr, p.get_deleter());
}
模板
std::unique\u ptr
静态\u唯一\u ptr\u转换(标准::唯一\u ptr&&p)
{
自动d=静态施法(p.释放());
返回std::unique_ptr(d,std::move(p.get_deleter());
}
模板
std::unique\u ptr
动态_-unique_-ptr_-cast(std::unique_-ptr&&p)
{
if(派生*result=dynamic_cast(p.get())){
p、 释放();
返回std::unique_ptr(结果,std::move(p.get_deleter());
}
return std::unique_ptr(nullptr,p.get_deleter());
}

函数采用右值引用,以确保您不会通过窃取传递给您的
unique\u ptr
而将地毯从呼叫者脚下拉出。

我会让
CastToDerived
采用
unique\u ptr&
。对于
shared\u ptr
,没有与
static\u pointer\u cast
等效的强制转换的原因是强制转换通常不会修改其参数。但是对于
unique\u ptr
,您必须将指针从参数移动到cast返回的对象。@dyp我认为
swap
在这种情况下也是一个不错的选择case@user2485710你能详细说明一下吗?@d7samurai(继续…)你的
CastToDerived
可以通过
CastToDerived(my_ptr.get())调用
(这是一个错误)和
CastToDerived(my_ptr.release())
(这是正确的)。为了防止前者,我建议使用类似于
CastToDerived(std::move(my_ptr))
的东西,它是显式的,并且可能不太容易出错。或者,在名称中显式显示它,比如
move\u static\u cast(my_ptr)
.So
unique\u ptr&&
(或者更确切地说是
unique\u ptr&&
,因为模板类型不能跨DLL边界公开)是否会隐式执行移动/传输?我是否可以直接执行这样的移动操作而不需要函数?这样的移动是否会保留原始唯一\u ptr中的删除器?您需要从源对象提取删除器并将其注入目标对象。类型很可能不够。@Praetor例如,ian[unique.ptr.single.asgn]说:“效果:通过调用
reset(u.release())
然后调用
std::forward(u.get\u deleter())
,将所有权从
u
转移到
。”所以我认为它定义得很好,尽管deleter没有出现在
发布的后置条件中
顺便说一句。deleter只能移动,这使得最终的return语句有点困难(你不能复制,也不应该移动,也许你不能默认构造)。如果只是移动,您可能需要
DefaultConstructible
;另一种方法是抛出异常而不是返回。@Praetorian您好,我一直在尝试使用此方法,并且在初始化unique_ptr()时使用自定义删除器时能够使其工作。但是,我不确定如何使用默认删除器()-在这种情况下,编译器会抱怨派生/基类删除程序之间没有可行的转换。是否可以将此代码与默认delteters一起使用?如果可以,请查看我的第二次粘贴,并告诉我如何使用正确的模板参数调用cast函数?谢谢:)@恶意
unique\u ptr
构造函数是
noexcept
。但是您的建议是,如果复制/移动删除程序会抛出错误,那么首先构造第二个
唯一的\u ptr
,然后
释放()
保留原始文件的所有权将是更简单的选择。
unique_ptr<Derived> CastToDerived(Base* obj) {
    return unique_ptr<Derived>(static_cast<Derived*>(obj));
}
template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
static_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    auto d = static_cast<Derived *>(p.release());
    return std::unique_ptr<Derived, Del>(d, std::move(p.get_deleter()));
}

template<typename Derived, typename Base, typename Del>
std::unique_ptr<Derived, Del> 
dynamic_unique_ptr_cast( std::unique_ptr<Base, Del>&& p )
{
    if(Derived *result = dynamic_cast<Derived *>(p.get())) {
        p.release();
        return std::unique_ptr<Derived, Del>(result, std::move(p.get_deleter()));
    }
    return std::unique_ptr<Derived, Del>(nullptr, p.get_deleter());
}