8

I want to check if a variable in a class was set or not? How can I do it?

enum Color {
   red,
   blue
};
class example {
   Color c;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set() {
       if (c == Color) {} // compile error
       if (c == NULL) {} // compile error
       return true;
   }

I want to know if the variable Color c was assigned or not ?

10
  • 3
    It's not possible. Unlike some other languages uninitialized variables will have an indeterminate value (that will seem almost random), and using them, even just to check their value, leads to undefined behavior. Commented May 30, 2018 at 11:35
  • 4
    You should define an unkown alternative in your enum and set it as default value for c Commented May 30, 2018 at 11:36
  • 2
    If you want to make sure that c always have a valid value, then you need to initialize c in a constructor. Commented May 30, 2018 at 11:38
  • 6
    i sense a xy problem, if your class had a proper constructor your problem would not exists, so what is the actual problem you are trying to solve? Commented May 30, 2018 at 11:41
  • 2
    to make the point even more clear: the purpose of classes is not to write getters and setters, and if you need to call a setter to bring your object into a valid state, then you did something wrong. If on the other hand "no_color" is a valid state then you should either use an std::optional or add a no_color to the enum Commented May 30, 2018 at 11:45

3 Answers 3

7

Other than having a value for not assigned (as in @code707's answer) you can do a few things.

Same approach, user can use the class uninitialized - mitigation

All are based on storing a bool if the user calls set correctly.

Use your get/set encapsulation to check if it has been set:

class example {
private:
    Color color;
    bool isColourSet = false;

public:
    Color get_color() const;

    void set_color(Color newCol) {
       color = newCol;
       isColourSet = true;
    }
...

Then you can use this bool in various ways depending on your desire:


Throw an exception

    Color get_color() const {
       if (!isColourSet) throw some_exception; // It wasnt Set!! Throw
       return color;
    }

This way, you don't have an extra enumeration element, and you protect against dishing out an undefined value by throwing an exception.


Returning an error code

If you don't want to throw an exception, you could pass a return argument and return an error:

ErrInt get_colour(Colour &out) const {
    if (!isColourSet) return STANDARD_ERROR_VAL;
    out = color;
    return STANDARD_SUCCESS_VALUE;
}

This is quite similar to the concept of a Bad Value in the enumeration.


Use std::optional

Since c++17 you also have a new way std::optional, where you can optionaly return (instead of throwing an exception or returning an error value).

class example {
public:
    std::optional<Color> get_colour() {
        return color;
    }
    void set_color(Color newColor) {
        color = newColor;
    }
private:
    std::optional<Color> color;
}

Then the user could use it as such:

auto myColor = myExample.get_colour();
if (myColour) { // Here you can check the optional
    myColour.get() // Do something with colour.
...

New approach, user cannot set the class in a bad state - redesign

As opposed to setting a value and having to check if it has been set correctly, perhaps you can design the class such that it can never be in an invalid state. Lets walk through how we might do this:

1 Type Safety

We don't want a user to be able to set a random value for color that we dont know about. In the current implementation enum will be a type that can be set with likely any int value! What does it mean when someone does set_color(538)? We can fix this with c++11 enum class:

enum class Color {
    RED,
    BLUE
}

// This now causes a compiler error:
set_color(523);
// You can only use it like this:
set_color(Color::Red);

2 Constructor Arguments

We can force the user to choose the initial colour by providing only a constructor that requires a color:

class example {
public:
    example(Color startColor) : color(startColor) {}        
...
private:
    Color c;
}

This means that a user will be unable to create the class without it having an initial color. Now we can add our set function in case the user wants to change the color:

void change_color(Color newColor) {
    color = newColor;
}

3 Conclusion

Now you have a class where the user can never get themselves into a situation where it is invalid. I believe this is much better then trying to detect if the user has stuffed up creating the class.

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

4 Comments

You could mention std::optional.
@YSC true, i am still catching up with fun c++17 stuff.
Note though with the power of std::optional, I'd keep as member variable an optional rather than a couple color+bool.
@YSC true, but my other answer is a better solution anyway. I will update this one as well.
4

What about having special value for "not assigned" ?

enum Color {
   nocolor,
   red,
   blue
};
class example {
   Color c = nocolor;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set() {
       if (c == nocolor) {} 

       return true;
   }

2 Comments

a null (starting) value paradigm!
you could make enum class Color {...} to remove implicit conversion, too.
2

If you are not hesitant to use the boost library, then maybe you can do it using boost::optional.

#include <boost/optional.hpp>

enum Color {
   red,
   blue
};

class example 
{
   boost::optional<Color> c;
   void set_color(Color c) { this->c = c; }
   Color get_color() { return c; }
   bool check_color_is_set()
   {
     if( c ){
       // color is set
       return true;
     }
     else
     {
       // color is not set.
       return false;
     }
   }
}

The default value of boost::optional<Color> c will be boost::none by default. You can perform normal if-checks on it and see if something has been set it or not.

Here is the documentation of Boost Optional for your reference.

NOTE : I haven't used the STL version of optional but if you are not interested in using Boost, you can always use std::optional as well.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.