4

I am writing a class that represents a button. This button may or may not have various attributes like text written on it, shortcut, texture or flat color fill. So if for example, this button doesn't have any texture set, texture drawing process is skipped.

My first solution was to use made up default values that would say that the given attribute is unused (if alpha value of color was 0 the color fill drawing would be skipped etc.).

Other option I have is to use newly added std::optional which would be much clearer and simpler to use.

Here are the 2 mentioned examples:

class Button { void draw() { if (fill) drawRectangle(*fill); if (sprite) drawSprite(*sprite); if (font) drawText(name, *font); } std::optional<std::string> font; std::optional<std::string> sprite; std::optional<Color> fill; } class Button { void draw() { if (fill.alpha != 0) drawRectangle(fill); if (sprite != "") drawSprite(sprite); if (font != "") drawText(name, font); } std::string font; std::string sprite; Color fill; } 

What can the advantages and disadvatages of using std::optional be in this case? What I'm mainly interested in, are the memory usage and overhead differences.

Also should I just, instead of using if to check whether optional contains value, call value() and catch the exception?

6
  • 3
    Regarding your question about using .value() and catching the exception instead of checking if it has a value: That is a bad idea. As the name suggests, exceptions are for exceptional cases, and the overhead caused by stack unrolling isn't negligible. Assuming that a lot of buttons e.g. wont have a color, the optional being empty isn't an exceptional case at all. Commented Apr 20, 2017 at 19:35
  • I don't see std::optional<std::string> as extremely useful, unless an empty string is different from no string at all. Commented Apr 20, 2017 at 19:48
  • std::optional was intended for function returns, not class members. This is a pretty wasteful thing to do. Also, note that sprite.empty() should be used over sprite == "". Commented Apr 20, 2017 at 19:53
  • 1
    std::optional has memory overhead (probably something similar to additional bool) Commented Apr 20, 2017 at 20:17
  • I don't see how std::optional may have any advantage. Also, consider major UI implementations such as AWT and .NET: an empty field is really empty, not "absent". Again, you get not value out of it. Commented Apr 20, 2017 at 20:59

2 Answers 2

7

As far as overhead goes, it's mostly in the form of space. optional always takes up whatever it's storing, plus a boolean, plus any extra padding to make alignment work out. For example, std::string is often implemented as 24 bytes with 8 byte alignment. An optional<string> would then be 25 bytes, but because of alignment it will end up being 32 bytes. For a primitive type (int, or an enum), then it will typically double the storage needed from 4 to 8 bytes, or something similar.

As far as performance goes, in this case there's going to be no difference outside cache effects (if the optimizer is smart). Comparing a std::string to an empty string literal will probably get optimized to a call to std::string::empty (you should probably write it that way), which is just checking if an integer is zero, which is the same as your comparison for Color, which is basically the same as checking whether a boolean is zero.

That said I do like optional; I think it more clearly communicates the intent of the code. However if you have very obvious sentinel values then maybe it's less valuable.

In some cases you can have your cake and eat it too with compact optional: https://github.com/akrzemi1/compact_optional. It has identical external interface to a regular optional, but you give it a sentinel value and it uses that sentinel to store the missing state. May not work well with all classes though.

Sign up to request clarification or add additional context in comments.

1 Comment

+1. Key takeaways are "more clearly communicates the intent" and "if you have very obvious sentinel values then maybe it's less valuable" Clearly communicating the intent take priority over basically everything except "easy to read" and "hard to misuse"
2

Although std::optional may incur the overhead of a extra boolean value, it also carries a descriptive purpose here: it fully expresses the concept you are trying to put into code, which makes that this code directly shows the reader what is going on. Because this is UI, and the boolean overhead is relatively small, I'd say go for it.

I contest the statement that std::optional was meant only for function returns. That would be ridiculously limited.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.