[英]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.