繁体   English   中英

铸造 `std::unique_ptr`

[英]Casting `std::unique_ptr`

通过以下function进行动态投射有什么问题吗?

template<typename Base, typename Derived>
    requires std::is_convertible_v<Derived&, Base&> &&
             std::is_polymorphic_v<Base>
inline std::unique_ptr<Derived> cast_to(std::unique_ptr<Base>&& ptr)
{
    return std::unique_ptr<Derived>(dynamic_cast<Derived*>(ptr.release()));
}

是的,如果转换失败,您的 function 很容易泄漏 memory。 考虑以下:

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

struct Derived1 : Base {};
struct Derived2 : Base {};

int main()
{
    std::unique_ptr<Base> bp = std::make_unique<Derived1>();

    // bp does not point to a Derived2, so this cast will fail
    auto d2p = cast_to<Base, Derived2>(std::move(bp));
    std::cout << bp.get() << '\n';  // 0
    std::cout << d2p.get() << '\n'; // also 0; object was leaked
}

演示

从这个片段中,您还可以看到另一个小问题:由于模板参数的顺序,您必须同时提供它们。 您不能让编译器推断Base因为它在Derived之前。


考虑到这两个问题,以下将是更好的实现:

template<typename Derived, typename Base>  // swap the order of template parameters
    requires std::is_convertible_v<Derived&, Base&> &&
             std::is_polymorphic_v<Base>
inline std::unique_ptr<Derived> cast_to(std::unique_ptr<Base>&& ptr)
{
    Derived* d = dynamic_cast<Derived*>(ptr.get());
    if (d) {
        ptr.release();
        return std::unique_ptr<Derived>(d);
    }
    return nullptr;  // object is still owned by ptr
}

这解决了上述两个问题:

int main()
{
    std::unique_ptr<Base> bp = std::make_unique<Derived1>();

    // No need to explicitly specify Base; the compiler can deduce that itself
    auto d2p = cast_to<Derived2>(std::move(bp));
    std::cout << bp.get() << '\n';  // not 0; no leak
    std::cout << d2p.get() << '\n'; // 0
}

演示

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM