-->

When to use boost::optional and when to use std::u

2020-02-03 05:28发布

问题:

From what I understand there are 2* ways you can implement a function that sometimes doesnt return a result(for example is person found in a list of ppl).

*- we ignore raw ptr version, pair with a bool flag, and exception when none found version.

boost::optional<Person> findPersonInList();

or

std::unique_ptr<Person> findPersonInList();

So are there any reasons to prefere one over the other?

回答1:

It depends: do you wish to return a handle or a copy.

If you wish to return a handle:

  • Person*
  • boost::optional<Person&>

are both acceptable choices. I tend to use a Ptr<Person> class which throws in case of null access, but that's my paranoia.

If you wish to return a copy:

  • boost::optional<Person> for non polymorphic classes
  • std::unique_ptr<Person> for polymorphic classes

because dynamic allocation incurs an overhead, so you only use it when necessary.



回答2:

The general answer is that your intentions are expressed by boost::optional and not by std::unique_ptr. That said, your special case of a find operation should probably conform to the standard library way of doing it, assuming that your underlying type has a concept of iterators: return an iterator to end() if no element is found, and an iterator to the element otherwise.



回答3:

boost::optional more clearly states your intention. You need to document explicitly that empty std::unique_ptr means there's no value to return



回答4:

There is a fourth way of doing it : make the function throw an exception if there is nothing found.

I know this does not really answer your question and therefore I apologize but maybe you hadn't thought about it.



回答5:

Ah, Xeo didn't show up yet?

Well, I told you this once, and I'll tell it again: these two are completely different objects with different purposes.

  • unique_ptr means I own an object. It's just different way of saying "I am an object". Thus, null unique_ptr is something that can attract attention. I was expecting an object, but I got nothing; the code must be wrong!
  • optional means I can sometimes be not initialized, but that's ok. In this case, there's no worries; if it's None, it's the behavior that has been thought of.

The fact that both implicitly convert to bool doesn't mean they can be used interchargeably. Use optional with code that is likely not to produce any output (reading a stream, for example). Use unique_ptr in factory objects; they will most likely create an object for you, and if not, throw an exception.

A conclusion regarding your example : find should return optional.



回答6:

Conceptually boils down to this, given the nullable requirement:

std::optional has value semantics, stack store.

std::unique_ptr has move semantics, heap store.

If you want value semantics and heap store, use std::indirect http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/p0201r1.pdf .

(If you want move semantics and stack store... I don't know. I guess it is a unique_ptr with a stack allocator?)



回答7:

So are there any reasons to prefere one over the other?

They express very different intent: optional says that the function may not give a result to give you (and that is not an error case). unique_ptr tells you something about ownership semantics (and is more acceptable to use with null, to express an error).

Usually I would use the one that expresses best the intent behind the interface.

For example, consider that you were writing a HTTP server, that attempts to parse a received buffer into a HTTP request object. When you attempt to parse an incomplete buffer, there is no error case, you simply have to wait and buffer more data, then try again.

I would express this using optional,to make it clear that the function may not return anything (and not returning anything is not an error case).

In case my parsing had to validate stuff (e.g. a regex parser should yield an error if the parsed expression is invalid regex) I would return a null unique_ptr, or better yet, throw an exception.