Home  >  Article  >  Backend Development  >  How to Safely Downcast a `unique_ptr` to `unique_ptr` in C ?

How to Safely Downcast a `unique_ptr` to `unique_ptr` in C ?

Barbara Streisand
Barbara StreisandOriginal
2024-11-19 20:37:03711browse

How to Safely Downcast a `unique_ptr` to `unique_ptr` in C  ?

Downcasting unique_ptr to unique_ptr

In the realm of object-oriented programming, inheritance plays a pivotal role in fostering code reuse and extensibility. However, situations may arise where one needs to "downcast" a unique_ptr object to a unique_ptr object, potentially with a different deleter function.

To address this challenge, consider a hypothetical scenario where an application employs several factories, each producing unique_ptr instances. These factories may internally offer access to various derived types, such as unique_ptr, unique_ptr, or unique_ptr. To illustrate:

unique_ptr<Base> DerivedAFactory() {
    return unique_ptr<Base>(new DerivedA);
}

The goal is to convert the pointer within the returned unique_ptr to a derived type, even if it differs from the original internal type. One can envision this process in pseudocode:

unique_ptr<Derived> ptr = static_cast<unique_ptr<Derived>>(DerivedAFactory());

However, this approach presents potential pitfalls. A more robust solution involves releasing the object from the unique_ptr, casting the raw pointer to the desired derived type, and reassigning it to a new unique_ptr with an appropriate deleter.

unique_ptr<Derived> CastToDerived(Base* obj) {
    return unique_ptr<Derived>(static_cast<Derived*>(obj));
}

This casting process should hold valid as long as the object is dynamically loaded from a DLL and released from the same context. However, when transferring ownership across different contexts, one must take care to supply a correct deleter alongside the pointer.

For added safety and flexibility, it is recommended to utilize function templates for casting:

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());
}

These templates ensure that the passed unique_ptr is not unintentionally stolen from the caller while providing both static and dynamic casting options. The static version can be employed when the pointer is known to be a Derived * without dynamic casting, while the dynamic version performs a runtime check using dynamic_cast.

The above is the detailed content of How to Safely Downcast a `unique_ptr` to `unique_ptr` in C ?. For more information, please follow other related articles on the PHP Chinese website!

Statement:
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn