Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
378 views
in Technique[技术] by (71.8m points)

c++ - Mix boost::optional and std::unique_ptr

I admit it: I'm in love with the concept of optional. The quality of my code has improved so much ever since I discovered it. Making it explicit whether a variable may or may not be valid is so much better than plain error codes and in-band signaling. It also allows me to not worry about having to read the contract in the documentation, or worrying about whether it's up-to-date: the code itself is the contract.

That said, sometimes I need to deal with std::unique_ptr. Objects of this type might be null or not; at a given point in the code is impossible to know whether the std::unique_ptr is supposed to have a value or not; it's impossible to know the contract from the code.

I would like to somehow mix optional (maybe withboost::optional) and std::unique_ptr, so that I have a dynamically allocated object with scope-destruction and proper copy/move behaviour that explicitly states that it may not have a value. That way, I can use this new type to make it explicit that a check for value is necessary and avoid unnecessary checks for plain std::unique_ptr.

Is there a tool for this inside the C++11 standard, boost or a popular enough library? I could accept defining my own class for this, but that would be the least preferred method (due to lack of thorough testing).

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

So to recap your question, you want:

  1. A non-optional type that is allocated by value/on the stack: You are happy directly using the object type for this.
  2. An optional type that is allocated by value/on the stack: You are happy using boost::optional for this (or you can use std::optional from C++17).
  3. A non-optional type that is allocated on the heap and owns the pointed-to object.
  4. An optional type that is allocated on the heap and owns the pointed-to object.

You are unhappy that you can express the difference between 1 and 2, but both 3 and 4 usually use the same type (std::unique_ptr). You suggest using std::unique_ptr for 3, never allowing nullptr, and some other thing for 4, but want to know what you can use. (In the comments you also accept the possibility of using std::unique_ptr with nullptr for 4 if something else can be found for 3.)

Literal answer to your question: you can simply use boost::optional<std::unique_ptr<T>> for 4 (while using a bare unique_ptr for 3 as you suggested).

Alternative literal answer to your question: As @StoryTeller said, you could define your own smart pointer type that is like unique_ptr but disallows nullptr, and use that for 3. A quicker (but very dirty) alternative is to force functions to return a pair of both a unique_ptr and a reference to that same object. Then only access the result through the reference, but only do so while the unique_ptr still exists:

template<class T>
using RefAndPtr = std::pair<T&, std::unique_ptr<T>>;

RefAndPtr<Foo> getFoo()
{
    std::unique_ptr<Foo> result = std::make_unique<Foo>();
    return RefAndPtr<Foo>(*result, std::move(result));
}

My actual suggestion: Just suck it up and use std::unique_ptr for both 3 and 4. Clarifying your intentions in the type system is a good thing, but too much of a good thing can be bad. Using either of the above options is just going to confuse the hell out of anyone that reads your code. And even if you stop people from incorrectly passing around nullptr, what's to stop them passing a pointer around to the wrong object, or already-freed memory, etc.? At some point you have to specify things outside of the type system.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...