【问题标题】:Check for value definedness in C++检查 C++ 中的值定义性
【发布时间】:2009-01-23 15:11:12
【问题描述】:

我正在使用 C++,我需要知道标量值(例如 double)是否“已定义”。如果需要,我还需要能够“取消定义”它:

class Foo {
public:
    double get_bar();

private:
    double bar;
    void calculate_bar() {
        bar = something();
    }
};

double Foo::get_bar() {
    if ( undefined(bar) )
        calculate_bar();
    return bar;
}

在 C++ 中可以吗?

谢谢

【问题讨论】:

    标签: c++ undef


    【解决方案1】:

    正如其他答案所说,C++ 没有这个概念。不过,您可以轻松解决它。

    您可以在构造函数中将 bar 初始化为未定义的值,通常为 -1.0 或类似的值。

    如果您知道calculate_bar 永远不会返回负值,您可以实现未定义的函数来检查

    一个更通用的解决方案是使用 bool 表示是否定义了 bar 并且您在构造函数中初始化为 false,并且当您第一次设置它时将其更改为 true。 boost::optional 以优雅的模板方式执行此操作。

    这就是您的代码示例的样子。

    class Foo {
    public:
        double get_bar();
        Foo() : barDefined(false) {}
    private:
        double bar;
        bool barDefined;
        void calculate_bar() {
            bar = something();
        }
    };
    
    double Foo::get_bar() {
        if ( barDefined == false ) {
            calculate_bar();
            barDefined = true;
        }
        return bar;
    }
    

    【讨论】:

    • boost::optional 真的很有趣
    • 大家对老-1有什么意见。我说不能得到尊重
    • 罗伯特·古尔德:这是一个哨兵价值。我会留给你研究为什么这通常被认为是一件坏事。
    • 如果您对 calculate_bar 的假设成立,我认为 -1 很好,因此您永远不会得到与未定义值相同的正确值。我也认为做类似的事情是个好习惯:const double UNDEFINED = -1.0。检查浮点类型的相等性也可能很危险。
    • 如果您可以将给定值指定为永远不会发生,则可以将其用作哨兵值,尽管我宁愿将其命名为 Laserallan 所说的那样。对标准的快速检查表明不能保证“double f(2.3); return f == 2.3;”将返回真;有人知道这方面的问题吗?
    【解决方案2】:

    正如其他人指出的那样,没有什么比“未定义”状态更重要的了。但你可能想看看boost.optional

    【讨论】:

      【解决方案3】:

      如果您的意思是在运行时,则没有这样的事情。如果bar 从未被初始化,它将会有任何随机位,这取决于对象的分配方式(一些分配器会将新内存初始化为全零)。

      编辑:由程序员处理构造函数中的对象状态和/或手动初始化方法,如init()

      【讨论】:

        【解决方案4】:

        C++ 没有原始类型的“未定义”状态。最接近浮点/双精度的是 NAN,但这确实有不同的含义。

        【讨论】:

        • 我自己为此使用了一个安静的 NaN (qNaN):en.wikipedia.org/wiki/NaN#Quiet_NaNs。 IEEE 编码在 NaN 中留下了许多未定义的位,允许您区分作为计算结果的 NaN 与显式分配的值。
        • 我不明白为什么你是唯一一个谈论它的人..
        【解决方案5】:

        为什么不维护一个单独的标志,该标志被初始化为 false,然后在计算 bar 时设置为 true。然后可以通过再次将标志设置为 false 来“取消定义”。

        if(!isBarValid)
        {
            calculateBar();
            isBarValid = true;
        }
        return bar;
        

        【讨论】:

          【解决方案6】:

          这在 C/C++ 中是不可能的,原语将始终分配一个值(主要是垃圾,无论它之前内存中的那个位置,除非在声明时显式分配)。我通常有一个占位符值(即指针的 0)表示未使用,但是这些也必须显式分配。如果你的 double 可以取任何值,那么我建议你在它旁边放一个布尔值,最初分配为 false,然后在你想要进行计算时测试/设置它。

          【讨论】:

            【解决方案7】:

            您可以试试Construct on first use idiom 并这样写get_bar()

            double & get_bar()
            {
                static double *bar = new double(something());
                return *bar;
            }
            

            当您拨打get_bar() 时,如果还没有人要求,它会为您生成bar。任何后续调用都将返回bar。正如链接页面所说,这在技术上不会泄漏内存,因为操作系统会在程序退出时回收它。

            更新:

            将返回值更改为double &,以便您修改bar

            【讨论】:

            • 我以前见过并使用过该技术——但为什么要分配内存,为什么不只是“静态双栏”? (即使是上课)
            • 列表中的下一个常见问题解答回答了这个问题。 :) parashift.com/c++-faq-lite/ctors.html#faq-10.14
            【解决方案8】:

            您必须使用额外的布尔值来完成。

            要使用额外的布尔值来实现,您可以尝试以下模板的逻辑:

            template<typename T>
            struct Defined
            {
             bool defined;
             T value;
             Defined() : defined(false) {}
             Defined(const T& value_) : defined(true), value(value_) {}
             ... and perhaps other operators here ...
             ... to make this behave even more like a T ...
            };
            

            【讨论】:

            • 这实际上是 boost::optional 如果你可以在你的程序中访问 boost。请注意,我是在这个帖子中了解到的 :) stackoverflow.com/questions/412611/…
            • C#的Nullable&lt;T&gt;模板也是这样实现的。
            【解决方案9】:

            bar 初始化为在构造函数中调用something() 函数时永远不会出现的某个值。

            例如:

            Foo(): bar(-1)
            {
            }
            

            然后检查get_bar函数中的值-1

            (嗯,Laserallan 也在 1 分钟前发布了这个答案 :-( ;-) )

            【讨论】:

            • 不幸的是,我的 double 可以是任何数字。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2019-03-19
            • 2013-02-06
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多