简体   繁体   中英

Is it sensible to use shared_ptr instead of unique_ptr as class member just to avoid implicit copy constructor deletion?

I would like to preserve the default copy-constructor of a large-ish (but say not particularly complex*) class, but ideally would like to replace some raw pointer member with a smart-pointer alternative.

unique_ptr seems to be the default for this, but it implicitly deletes the copy constructor for my class.

shared_ptr instead would allow me to preserve the class' copy constructor. Could that likely be a good reason to simply stick to shared_ptr, even if I do not genuinely want to 'share' the resource; I really only want to preserve the readily available copy constructor (annoying to write a manual copy constructor for the entire class, just to replace a pointer with a unique_ptr), just as I had it when I still used raw pointer.

Searching for when to use shared_ptr vs. unique_ptr, I never see the simple preservation of the copy-constructor indicated as a possible key reason to use shared_ptr (possible exception https://stackoverflow.com/a/16030118/3673329 but not giving any detail), but I also do not directly see any reason why this could not be a valid choice.

I reckon shared_ptr may be a bit more resource intensive, but assume my case where this is no real problem.

*In particular, the default/shallow copying of the class was fine for my purposes as long as I used raw pointer members instead of smart ones.

If the only reason to use std::shared_ptr is to retain default copy constructibility of your class, you prioritize ease of use over the intended semantics of your class with respect to resource handling. In my opinion, you have to decide up front whether the class shall share its resources or exclusively own it. If you are unsure whether the class should share its resources with copied instances or not, something else in the design might at least be suspicious.

There might be an exception to this guideline, and that is std::shared_ptr<const YourType> . In the case of read only access, it might be acceptable to use such a technique to allow for default copy construction (although in a different context, here is where Sean Parent says that std::shared_ptr<const T> is acceptable to obtain value semantics).

Note one further implication: if you share a std::shared_ptr instance, you are not only sharing state and functionality of the pointee, you also share lifetime control. If the latter is not what you intend, just share a reference (preferable) or a raw pointer to the pointee, with access eg via a getter-like member function. If the consuming parts of your class can't know whether the pointee is still alive or has already been destroyed, a std::weak_ptr could be an option.

There is still a great deal of advantage in using a unique_ptr and providing the missing copy operations manually.

You get the correctness guarantees plus an easy customisation point for inner object cloning.

example:

#include <memory>


struct LargeImplObject
{
    int x[1000];
};

struct CopyableHandle
{
    using impl_class = LargeImplObject;
    using implementation_type = std::unique_ptr<impl_class>;

    CopyableHandle()
    : impl_(construct())
    {}

    CopyableHandle(CopyableHandle&&) noexcept = default;
    CopyableHandle& operator=(CopyableHandle&&) noexcept = default;

    CopyableHandle(CopyableHandle const& other)
    : impl_(other.clone())
    {}

    CopyableHandle& operator=(CopyableHandle const& other)
    {
        impl_ = other.clone();
        return *this;
    }

    // note: no destructor

private:

    // customisation points
    static auto construct() -> implementation_type
    {
        return std::make_unique<impl_class>();
    }

    auto clone() const -> implementation_type
    {
        return std::make_unique<impl_class>(*impl_);
    }


    implementation_type impl_;
};

int main()
{
    auto a = CopyableHandle();
    auto b = a;
    auto c = std::move(a);
    a = std::move(c);
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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