std::Optional 与“未使用/默认”值的使用

Mar*_*ťko 4 c++ option-type c++17

我正在编写一个代表按钮的类。该按钮可能有也可能没有各种属性,例如上面写的文本、快捷方式、纹理或平面颜色填充。因此,例如,如果此按钮没有任何纹理集,则跳过纹理绘制过程。

我的第一个解决方案是使用虚构的默认值,这表示给定的属性未使用(如果颜色的 alpha 值为 0,则将跳过颜色填充绘图等)。

我的其他选择是使用新添加的 std::Optional ,这会更清晰且更易于使用。

以下是提到的 2 个示例:

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;
}
Run Code Online (Sandbox Code Playgroud)

在这种情况下使用 std::Optional 的优点和缺点是什么?我主要感兴趣的是内存使用和开销差异。

另外,我是否应该调用 value() 并捕获异常,而不是使用 if 来检查可选是否包含值?

Nir*_*man 6

就开销而言,它主要以空间的形式存在。optional总是占用它存储的任何内容,加上一个布尔值,再加上任何额外的填充来进行对齐。例如,std::string通常实现为具有 8 字节对齐的 24 字节。Anoptional<string>将为 25 字节,但由于对齐,最终将变为 32 字节。对于原始类型(int 或 enum),通常会将所需的存储量从 4 字节增加到 8 字节或类似的值。

就性能而言,在这种情况下,缓存效果之外不会有任何差异(如果优化器很聪明)。将 astd::string与空字符串文字进行比较可能会优化为调用std::string::empty(您可能应该这样写),这只是检查整数是否为零,这与您的比较相同Color,这基本上与检查布尔值是否为零。

这就是说我确实喜欢optional;我认为它更清楚地传达了代码的意图。然而,如果你有非常明显的哨兵值,那么它的价值可能就不那么高了。

在某些情况下,您可以通过紧凑的可选选项鱼与熊掌兼得: https: //github.com/akrzemi1/compact_Optional。它具有与常规选项相同的外部接口,但是您给它一个哨兵值,它使用该哨兵来存储丢失的状态。但可能不适用于所有课程。

  • +1。关键要点是“**更清楚地传达意图**”和“**如果你有非常明显的哨兵值,那么它的价值可能就不那么高了**”清晰地传达意图基本上优先于除“易于阅读”和“之外的所有内容”难以滥用” (3认同)