Check for value definedness in C++

2020-04-05 12:14发布

问题:

I'm working in C++ and I need to know if a scalar value (for instance a double) is "defined" or not. I also need to be able to "undef" it if needed:

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;
}

Is it possible in C++?

Thanks

回答1:

As the other answers says, C++ doesn't have this concept. You can easily work around it though.

Either you can have an undefined value which you initialize bar to in the constructor, typically -1.0 or something similar.

If you know that calculate_bar never returns negative values you can implement the undefined function as a check for < 0.0.

A more general solution is having a bool saying whether bar is defined yet that you initialized to false in the constructor and when you first set it you change it to true. boost::optional does this in an elegant templated way.

This is what the code example you have would look like.

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;
}


回答2:

As others pointed out, there is nothing like an "undefined" state. But you may want to look into boost.optional



回答3:

If you mean at run-time, there is no such thing. If bar is never initialized, it will have whatever random bits happen to be there, depending on how the object is allocated (some allocators will initialize new memory to all-zero).

edit: it's up to the programmer to handle object state in constructors and/or manual initialization methods like init()



回答4:

Why not maintain a separate flag that gets initialized to false and then gets set to true when bar is calculated. It can then be 'undefed' by setting the flag to false again.

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


回答5:

C++ does not have an "undefined" state for primitive types. The closest available for float/double would be NAN, but that really has a different meaning.



回答6:

This is not possible in C/C++, primitives will always a value assigned (mostly garbage, whatever was on that spot in memory before it, unless explicitly assigned at declaration). I's common to have a placeholder value (i.e. 0 for pointers) which denotes not-used, however these have to be explicitly assigned as well. If your double can take on any value, then I suggest you put a boolean next to it, assigned to false initially, and test/set that one when you want to do your calculation.



回答7:

You must do it by using an extra boolean.

To implement using an extra boolean, you could try logic like the following template:

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 ...
};


回答8:

You could try the Construct on first use idiom and write get_bar() this way:

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

When you call get_bar() it will make bar for you if no one has asked for it yet. Any subsequent calls will just return bar. As the linked page says, this doesn't technically leak memory because the OS will reclaim it when the program exits.

UPDATE:

Changed the return value to double & to allow you to modify bar.



回答9:

Initialize bar to some value which can never occur when you call the something() function in the constructor.

For example:

Foo(): bar(-1)
{
}

Then check for the value -1 in the get_bar function.

(hmmm Laserallan also posted that answer 1 minute before :-( ;-) )



标签: c++ undef