rogerw
rogerw

Reputation: 75

Detect initialized variables

Is there a way to check if certain variable is initialized before some point in a program?

For example, how to check if certain variable is initialized somewhere before the IfStmt node? Methods from VarDecl class (hasInit() and getInit()) are not enough because of the following situation:

int x = 0; // hasInit() return true

int y;
...
y = 0; // initialized here, but hasInit() returns false
...
if (...) {}

Upvotes: 2

Views: 175

Answers (2)

tangy
tangy

Reputation: 3276

Firstly as mentioned in the comments:

int y = 0; // initialization
int y; y = 0; // assignment

Let's assume you want to detect assignment. One simple way could be wrap the integer you want to track in a struct and write a custom operator = (int). For example:

struct Foo 
{
   Foo() {std::cout << "default init" << std::endl;} 
   Foo& operator = (int elem) 
   { 
      cout<<"Int-Assignment operator called "<<endl;
      x = elem;
      is_assigned = true;
      return *this;
   }
   int x = 0; // default initialized to 0
   bool is_assigned = false; // default initialized to false
}; 

Now let's see what happens:

int main() 
{ 
  Foo t1; 
  // t1.is_assigned is false
  t1 = 0; 
  // t1.is_assigned is true
  return 0; 
} 

You could use something like this or a variant if needed. Here's the code running online corresponding to the above.

Is this what you wanted?

Upvotes: 1

Hiroki
Hiroki

Reputation: 2880

If you maintain a product written by C++ code and hope to remove ugly indeterminate variables, a reasonable way to do it is defining an initializing function or lambda f, and then declare a local variable as const auto x = f(...); from the get-go.

OTOH, if you delay the value asignment on purpose, there are several methods to detect the value is assigned or not. I just came up with following methods.


std::optional

In C++17 and over, std::optional<T> enables us to detect whether values are assigned or not. std::optional::has_value and std::optional::value correspond to your hasInit and getInit respectively as follows:

DEMO

#include <iostream>
#include <optional>

template<typename T>
void checkInitialization(const std::optional<T>& a)
{
    if(a.has_value()){            
        std::cout << "Value is assigned by " << a.value() << "." << std::endl;
    }
    else{
        std::cout << "Value is still not assigned." << std::endl;
    }
}

int main(void)
{
    std::optional<int> x;

    checkInitialization(x); // Value is still not assigned
    
    x = 1;
    checkInitialization(x); // Value is assigned

    return 0;
}

The output is as follows:

Value is still not assigned.

Value is assigned by 1.


std::unique_ptr

We can also check it using std::unique_ptr<T> which is introduced from C++11. First we define a variable as std::unique_ptr<T> x; where (x == nullptr) is still true. Later on, we assign a value by x = std::unique_ptr<int>(new int(1)) and then (x == nullptr) becomes false. (In C++14 x = std::make_unique<int>(1) works and is simple.) Thus we can again get the previous output with the following code:

DEMO

#include <iostream>
#include <memory>

template<typename T>
bool hasInit(const std::unique_ptr<T>& a)
{
    return (a != nullptr);
}

template<typename T>
const T& getInit(const std::unique_ptr<T>& a)
{
    return *a;
}

template<typename T>
void checkInitialization(const std::unique_ptr<T>& a)
{
    if(hasInit(a)){   
        std::cout << "Value is assigned by " << getInit(a) << "." << std::endl;
    }
    else{
        std::cout << "Value is still not assigned." << std::endl;
    }
}

int main(void)
{
    std::unique_ptr<int> x;

    checkInitialization(x); // Uninitialized
    
    x = std::unique_ptr<int>(new int(1));
    //x = std::make_unique<int>(1); // C++14
    checkInitialization(x); // Initialized

    return 0;
}

std::pair

We can also apply std::pair<bool, T> where std::pair::first and std::pair::second correspond to your hasInit and getInit respectively. We again get the previous output:

DEMO

#include <iostream>
#include <utility>

template<typename T>
void checkInitialization(const std::pair<bool, T>& a)
{
    if(a.first){   
        std::cout << "Value is assigned by " << a.second << "." << std::endl;
    }
    else{
        std::cout << "Value is still not assigned." << std::endl;
    }
}

int main(void)
{
    std::pair<bool, int> x{false, 0};

    checkInitialization(x); // Uninitialized
    
    x = {true, 1};
    checkInitialization(x); // Initialized

    return 0;
}

Upvotes: 1

Related Questions