简体   繁体   中英

std::unique_ptr::release() vs std::move()

I have a class that represents a runtime context and builds a tree, the tree root is held in a unique_ptr . When building the tree is done I want to extract the tree. This is how it looks (not runnable, this is not a debugging question):

class Context {
    private:
    std::unique_ptr<Node> root{new Node{}};
    public:
    // imagine a constructor, attributes and methods to build a tree
    std::unique_ptr<Node> extractTree() {
        return std::move(this->root);
    }
};

So I used std::move() to extract the root node from the Context instance.

However there are alternatives to using std::move() eg:

std::unique_ptr<Node> extractTree() {
    // This seems less intuitive to me
    return std::unique_ptr<Node>{this->root.release()};
}

Is std::move() the best choice?

You should definitely go with the first version as the second one basically does the everything the first version does with more code and less readability.

Philosophically speaking, the second version moves the unique pointer, no more, no less. so why going around the table instead of using the already existing, more readable and more idiomatic std::unique_ptr(std::unique_ptr&&) ?

And lastly, if your smart pointer somewhere in the future will hold custom deleter , the first version will make sure the deleter moves as well, the second version does not moves the deleter. I can definitely imagine a programmer building non-custom deleter unique pointer out of custom-deleter unique_pointer with using release . With move semantics, the program will fail to compile.

What you're doing is dangerous. Once you've called getTree() , you must not call it a second time, which is not clear from the interface. You may want to reconsider your design (eg a shared_ptr might do a better job, or simply store the root as a raw pointer and manually take care of the deallocation).

Anyway, using std::move is the better option of the two if you want to stick with your design as it makes your intent more clear.

EDIT: apparently 'must not' has a special meaning of forbideness in English I was not aware of. It is fine to call the function twice or as many times as you want, but will not return a pointer to a valid object if done consecutively.

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