boost::optional For Pointers

Started by
38 comments, last by Hodgman 13 years, 7 months ago
I thought I'd pose a quick question to the community here to get some feedback on a convention I'm using in a side project: using boost::optional to wrap pointers where a non-exceptional invalid state is expected. In other words, I'm basically pretending null pointers don't exist and using optional wherever you would otherwise be testing for a null pointer.

So far even just using my own code it's helped me avoid a few dumb mistakes, but I can't help but think it might really annoy some C++ programmers out there. So, does anybody out there think this convention is overly cumbersome/excessive? Or even more importantly, counterproductive in some way?
Advertisement
A rose by any other name....

What do you return instead of null pointer?

In what way is this better than NullObject?
I don't get it. What's wrong with null? In any case, what's your expected result if you do the following:

if (foo){}
I guess I didn't explain the motivation behind doing things this way. There are really two reasons: consistency with non-pointer types, and hinting good practice to the programmer. For the first, the same software has several instances where optionals are used elsewhere for types which don't have an inherent null value, and just using optional for ALL types makes the syntax consistent throughout the program. For the second, seeing optional<pointer> just simply makes it a lot more obvious that, "uninitialized values are a very real possibility here--account for them."

Part of what I'm playing around with in this side project is how far I can go with actually enforcing good usage practices before it just gets annoying. Trying to find that line where it goes from, "this helps me not make mistakes," to, "this is just annoying."

Quote:Original post by Antheus
In what way is this better than NullObject?


It's no better because that's precisely what it is. It's just an implementation that makes it semantically obvious exactly what's going on. I guess I should mention that there are places in the same library where null pointers will never be returned during non-exceptional execution, and I'm testing this out to make the distinction of where this is more obvious.
It seems a bit awkward to wrap a pointer in a boost::optional. Isn't the syntax for reading a member going to be (*object)->member? There is probably some overhead as well because to make boost::oprional work with ints and other variables it must store a bool variable somewhere to indicates wether it is set or not set.

I think a better choise is to make a simple smart pointer. Take boost::intrusive_pointer and strip out reference counting from it and call it something like non_null_ptr<T>.

You may also use refreences to show that an object is not null. Although I use it mostly for simple data carrying objects. When passing something like a texture which is usually passed by pointer (or smart pointer) or some object which may be stored for later, passing by reference feels wrong.
Quote:Original post by jonathanjansson
It seems a bit awkward to wrap a pointer in a boost::optional. Isn't the syntax for reading a member going to be (*object)->member? There is probably some overhead as well because to make boost::oprional work with ints and other variables it must store a bool variable somewhere to indicates wether it is set or not set.

I think a better choise is to make a simple smart pointer. Take boost::intrusive_pointer and strip out reference counting from it and call it something like non_null_ptr<T>.

You may also use refreences to show that an object is not null. Although I use it mostly for simple data carrying objects. When passing something like a texture which is usually passed by pointer (or smart pointer) or some object which may be stored for later, passing by reference feels wrong.


Well, everything is already wrapped in smart pointers, and I'd like to stick to just one pointer type for consistency sake. If I do end up going with this, I'll probably do some kind of specialization of optional for my specific smart pointer type so that it only takes a single dereference to get at the pointee.

Using references like that wouldn't really work since the memory in question is allocated from the freestore and being managed with smart pointers. I'd have to make some kind of funky smart pointer that deals in references rather than pointers, which would just be strange.
Quote:Original post by Antheus
What do you return instead of null pointer?


A default-constructed boost::optional<T*>, of course.

Quote:In what way is this better than NullObject?


I don't know. In what ways is an implementation of a pattern better than the pattern?

The point of what OP is doing is simply to make explicit the concept of nullness of pointers. Instead of pointers having a magical value that indicates that they don't really point at anything, the "optional" pointer is conceptually simply not there.

I don't like it, though. We're adding overhead (boost::optional<T> adds extra data for a flag to indicate whether the underlying data actually represents a T instance - even if T is a pointer, AFAIK), potentially duplicating our signal (since we can still have a NULL pointer in addition to a non-pointer), and spurning one of the best-established idioms of the language.
Yeah, this seems like a foolish consistency. Pointers are already optional, and boost::optional is designed to mimic the syntax of null/not-null pointers.

If you really feel like getting your boost::optional rocks off, how 'bout passing around optional references? Those are even more like pointers, and without the weird two-kinds-of-null thing you've got going on there.
Quote:Original post by Zahlman
Quote:Original post by Antheus
What do you return instead of null pointer?


A default-constructed boost::optional<T*>, of course.

Quote:In what way is this better than NullObject?


I don't know. In what ways is an implementation of a pattern better than the pattern?

The point of what OP is doing is simply to make explicit the concept of nullness of pointers. Instead of pointers having a magical value that indicates that they don't really point at anything, the "optional" pointer is conceptually simply not there.

I don't like it, though. We're adding overhead (boost::optional<T> adds extra data for a flag to indicate whether the underlying data actually represents a T instance - even if T is a pointer, AFAIK), potentially duplicating our signal (since we can still have a NULL pointer in addition to a non-pointer), and spurning one of the best-established idioms of the language.


When I think about it some more, I think maybe the OP wants to treat NULL (i.e. the actual built-in pointer NULL value) differently from this other value. In essence, he doesn't want NULL to be a special value which conceptually means "no value", but rather he wants NULL to be "just another legitimate value like anything else". So just using NULL for everything doesn't even work for what he wants.

That being said, it makes me wonder if there's some other kind of design problem going on. In any case, I cringe at this idea, but it's hard to come up with something better without being given an actual problem to solve.
I like his idea, and understand his two reasons. the consistency thing is obvious. the other one might not.

there are things that should never fail, but might. those return a 0 pointer. there are things, that are expected to fail, those are then in optional. i get his idea.

Model* mainCharacter = content->Load("Main Character.mesh");
as this should not error. if it does, it causes an exception (normally)

Server* connection = connectToMultiplayerServer();
this can be valid to not return something, as it is valid to not have an internet connection.

optional<Server*> connection = connectToMultiplayerServer();
makes sense there. the optional shows if there's a connection, or not. null can not happen, as this would have thrown before.

optional<Object*> hit = World.FindCollision(mainCharacter);
i'd use it in such cases quite often.

ads some clarity to the code, that, indeed, the return value is optional, and not expected.
If that's not the help you're after then you're going to have to explain the problem better than what you have. - joanusdmentia

My Page davepermen.net | My Music on Bandcamp and on Soundcloud

This topic is closed to new replies.

Advertisement