When to use boost::optional and when to use std::unique_ptr in cases when you want to implement a function that can return “nothing”?

两盒软妹~` 提交于 2019-11-28 06:52:41

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.

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.

Andriy Tylychko

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

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.

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.

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?)

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.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!