unique_ptr的static_pointer_cast替代方案

sky*_*ack 22 c++ casting shared-ptr unique-ptr c++11

我知道使用static_pointer_castwith unique_ptr会导致所包含数据的共享所有权.
换句话说,我想做的是:

unique_ptr<Base> foo = fooFactory();
// do something for a while
unique_ptr<Derived> bar = static_unique_pointer_cast<Derived>(foo);
Run Code Online (Sandbox Code Playgroud)

无论如何,这样做的结果是两个unique_ptr不应该同时存在,所以它只是被禁止.
是的,绝对有道理,这就是为什么不存在static_unique_pointer_cast确实存在的原因.

到目前为止,在我想存储指向这些基类的指针的情况下,但我还需要将它们转换为某些派生类(例如,想象一下涉及类型擦除的场景),我使用了shared_ptrs因为我的'如上所述.

无论如何,我猜测是否有替代方案可以shared_ptr解决这样的问题,或者在这种情况下它们是否真的是最佳解决方案.

Ane*_*dar 32

原始指针

你的问题的解决方案是获取原始(非拥有)指针并将其unique_ptr<Base>强制转换- 然后让原始指针超出范围,让剩余的指针控制所拥有对象的生命周期.

像这样:

unique_ptr<Base> foo = fooFactory();

{
    Base* tempBase = foo.get();
    Derived* tempDerived = static_cast<Derived*>(tempBase);
} //tempBase and tempDerived go out of scope here, but foo remains -> no need to delete
Run Code Online (Sandbox Code Playgroud)

Unique_pointer_cast

另一种选择是使用release()函数将unique_ptr其包装到另一个unique_ptr中.

像这样

template<typename TO, typename FROM>
unique_ptr<TO> static_unique_pointer_cast (unique_ptr<FROM>&& old){
    return unique_ptr<TO>{static_cast<TO*>(old.release())};
    //conversion: unique_ptr<FROM>->FROM*->TO*->unique_ptr<TO>
}

unique_ptr<Base> foo = fooFactory();

unique_ptr<Derived> foo2 = static_unique_pointer_cast<Derived>(std::move(foo));
Run Code Online (Sandbox Code Playgroud)

请记住,这会使旧指针无效 foo

从原始指针引用

只是为了完整答案,这个解决方案实际上是由OP在评论中对原始指针的一个小修改.

与使用原始指针类似,可以转换原始指针,然后通过derefering从中创建引用.在这种情况下,重要的是要保证创建的引用的生命周期不超过unique_ptr的生命周期.

样品:

unique_ptr<Base> foo = fooFactory();
Derived& bar = *(static_cast<Derived*>(foo.get()));
//do not use bar after foo goes out of scope
Run Code Online (Sandbox Code Playgroud)

  • 为什么不反转那些模板参数的顺序,并推导出`FROM`,就像`std :: static_pointer_cast`一样? (2认同)
  • @skypjack 出现的问题是:谁是所指向对象的所有者(即负责删除的对象)?一次只有一个指针?-&gt; 使用 unique_ptr,一次可能只有一个。多个(可能属于不同类别)?-&gt; 使用共享指针。对于不负责删除的指针,请使用原始指针。如果您决定拥有一个所有者,那么它们可能是获取指向同一对象的不同类的指针,同时保留原始对象的所有权的唯一方法。 (2认同)

Jon*_*ely 7

我知道将static_pointer_cast与unique_ptr一起使用会导致所包含数据的共享所有权.

只有你定义得很糟糕.显而易见的解决方案是转移所有权,以便源对象最终为空.

如果您不想转让所有权,那么只需使用原始指针即可.

或者,如果你想要两个所有者然后使用shared_ptr.

看起来你的问题只是部分关于实际的转换操作,部分只是指针缺乏明确的所有权政策.如果您需要多个所有者,无论他们是否使用相同类型,或者是否将其转换为其他类型,那么您不应该使用unique_ptr.

无论如何,使用两个不应该同时存在的unique_ptr会导致结果,因此它被禁止.
是的,绝对有道理,这就是为什么不存在像static_unique_pointer_cast那样的东西.

不,这不是它不存在的原因.它不存在,因为如果你需要它自己编写它是微不足道的(并且只要你给它独特所有权的理智语义).只需将指针弹出release(),然后将其放入另一个指针中unique_ptr.简单安全.

情况并非如此shared_ptr,"明显的"解决方案没有做正确的事情:

shared_ptr<Derived> p2(static_cast<Derived*>(p1.get());
Run Code Online (Sandbox Code Playgroud)

这将创建两个shared_ptr拥有相同指针的不同对象,但不共享所有权(即它们都会尝试删除它,导致未定义的行为).

shared_ptr第一次标准化时,没有安全的方法来做到这一点,因此static_pointer_cast定义了相关的铸造功能.他们需要访问shared_ptr簿记信息的实施细节才能工作.

但是,在C++ 11期间,标准化过程shared_ptr通过添加"别名构造函数"得到了增强,它允许您简单安全地执行转换:

shared_ptr<Derived> p2(p1, static_cast<Derived*>(p1.get());
Run Code Online (Sandbox Code Playgroud)

如果这个特征一直是其中的一部分,shared_ptr那么它可能,甚至可能是static_pointer_cast永远不会被定义的.

  • `std :: exchange`很容易写,没有人使用它.它是如何进入的?:-) (2认同)