Подтвердить что ты не робот

Проверка инициализации переменной

Похоже, это будет дубликат, но, возможно, это так очевидно, что его не спрашивали...

Это правильный способ проверить, инициализирована ли переменная (не указатель) в классе С++?

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with mCharacter.
    }

    if ( ! mDecimal )
    {
        // define mDecimal.
    }
}
4b9b3361

Ответ 1

Нет способа проверить содержимое переменной undefined или нет. Лучшее, что вы можете сделать, это назначить значение сигнала/оповещения (например, в конструкторе), чтобы указать, что дальнейшая инициализация должна быть выполнена.

Ответ 2

Переменная, которая не определена, вызовет ошибку компиляции.

То, что вы спрашиваете, это проверить, является ли оно инициализированным. Но инициализация - это просто значение, которое вы должны выбрать и назначить в конструкторе.

Например:

class MyClass
{
    MyClass() : mCharacter('0'), mDecimal(-1.0){};
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter != '0')
    {
        // touched after the constructor
        // do something with mCharacter.
    }

    if ( mDecimal != -1.0 )
    {
        // touched after the constructor
        // define mDecimal.
    }
}

Вы должны инициализировать значение по умолчанию, которое будет означать что-то в контексте вашей логики, конечно.

Ответ 3

В зависимости от ваших приложений (и особенно, если вы уже используете boost), вы можете посмотреть на boost::optional.

(ОБНОВЛЕНИЕ: Начиная с С++ 17, option теперь является частью стандартной библиотеки, как std::optional)

У него есть свойство, которое вы ищете, отслеживая, содержит ли слот значение или нет. По умолчанию он сконструирован так, что не содержит значения и оценивается как false, но если он оценивается как true, вам разрешается разыменовать его и получать упакованное значение.

class MyClass
{
    void SomeMethod();

    optional<char> mCharacter;
    optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        // do something with *mCharacter.
        // (note you must use the dereference operator)
    }

    if ( ! mDecimal )
    {
        // call mDecimal.reset(expression)
        // (this is how you assign an optional)
    }
}

Больше примеров в документации Boost.

Ответ 4

В С++ 17 вы можете использовать std::optional для проверки инициализации переменной:

#include <optional>
#include <iostream>  // needed only for std::cout

int main() {
    std::optional<int> variable;

    if (!variable) {
        std::cout << "variable is NOT initialized\n";
    }

    variable = 3;

    if (variable) {
        std::cout << "variable IS initialized and is set to " << *variable << '\n';
    }

    return 0;
}

Это даст результат:

variable is NOT initialized
variable IS initialized and is set to 3

Чтобы использовать std::optional option в предоставленном вами коде, вам нужно включить стандартный заголовок библиотеки <optional> и добавить std::optional<...> в соответствующие объявления переменных:

#include <optional>

class MyClass
{
    void SomeMethod();

    std::optional<char> mCharacter;
    std::optional<double> mDecimal;
};

void MyClass::SomeMethod()
{
    if ( mCharacter )
    {
        std::cout << *mCharacter;  // do something with mCharacter.
    }

    if ( ! mDecimal )
    {
        mDecimal = 3.14159;  // define mDecimal.
    }
}

Ответ 5

По умолчанию, нет, вы не можете знать, была ли или не указана переменная (или указатель). Однако, поскольку все остальные говорят вам о "легком" или "нормальном" подходе, я расскажу вам еще об этом. Здесь, как вы могли бы отслеживать что-то подобное (нет, я лично никогда не сделаю этого, но, возможно, у вас разные потребности, чем у меня).

class MyVeryCoolInteger
{
public:
    MyVeryCoolInteger() : m_initialized(false) {}

    MyVeryCoolInteger& operator=(const int integer)
    {
        m_initialized = true;
        m_int = integer;
        return *this;
    }

    int value()
    {
        return m_int;
    }

    bool isInitialized()
    {
        return m_initialized;
    }

private:
    int m_int;
    bool m_initialized;
};

Ответ 6

С С++ - 11 вы можете рассмотреть возможность хранения переменной с помощью интеллектуальных указателей. Рассмотрим этот MVE, где поведение toString() зависит от инициализации bar или нет:

#include <memory>
#include <sstream>

class Foo {

private:
    std::shared_ptr<int> bar;

public:
    Foo() {}
    void setBar(int bar) {
        this->bar = std::make_shared<int>(bar);
    }
    std::string toString() const {
        std::ostringstream ss;
        if (bar)           // bar was set
            ss << *bar;
        else               // bar was never set
            ss << "unset";
        return ss.str();
    }
};

Используя этот код

Foo f;
std::cout << f.toString() << std::endl;
f.setBar(42);
std::cout << f.toString() << std::endl;

выводит вывод

unset
42

Ответ 7

Нет разумного способа проверить, было ли инициализировано значение.

Если вам интересно, было ли что-то инициализировано, вместо того, чтобы пытаться проверить его, поместите код в конструктор (ы), чтобы убедиться, что они всегда инициализированы и выполняются с ним.

Ответ 8

Так как MyClass является классом класса POD, те нестатические члены данных будут иметь неопределенные начальные значения при создании нестатического экземпляра MyClass, поэтому нет, это не является допустимым способом проверить, являются ли они были инициализированы определенным ненулевым значением... вы в основном предполагаете, что они будут инициализированы нулями, что не будет иметь место, поскольку вы не инициализировали значение в конструкторе.

Если вы хотите инициализировать нулевые члены класса, не статические данные, лучше всего создать список инициализации и класс-конструктор. Например:

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;

    public:
        MyClass();
};

MyClass::MyClass(): mCharacter(0), mDecimal(0) {}

Список инициализации в конструкторе выше значения инициализирует ваши данные-члены до нуля. Теперь вы можете правильно предположить, что любое ненулевое значение для mCharacter и mDecimal должно быть специально задано вами где-то еще в вашем коде и содержать ненулевые значения, которые вы можете корректно выполнять.

Ответ 9

Если вы имеете в виду, как проверить, были ли инициализированы переменные-члены, вы можете сделать это, присвоив им значения sentinel в конструкторе. Выберите значения дозорности как значения, которые никогда не будут возникать при нормальном использовании этой переменной. Если весь диапазон переменных считается допустимым, вы можете создать логическое значение, чтобы указать, было ли оно инициализировано.

#include <limits>

class MyClass
{
    void SomeMethod();

    char mCharacter;
    bool isCharacterInitialized;
    double mDecimal;

    MyClass()
    : isCharacterInitialized(false)
    , mDecimal( std::numeric_limits<double>::quiet_NaN() )
    {}


};


void MyClass::SomeMethod()
{
    if ( isCharacterInitialized == false )
    {
        // do something with mCharacter.
    }

    if ( mDecimal != mDecimal ) // if true, mDecimal == NaN
    {
        // define mDecimal.
    }
}

Ответ 10

На языке С++ нет способа проверить, инициализирована ли переменная или нет (хотя типы классов с конструкторами будут инициализированы автоматически).

Вместо этого вам нужно предоставить конструктор (ы), который инициализирует ваш класс действительным состоянием. Статические проверки кода (и, возможно, некоторые компиляторы) могут помочь вам найти недостающие переменные в конструкторах. Таким образом, вам не нужно беспокоиться о том, чтобы быть в фиктивном состоянии, а проверки if в вашем методе могут полностью исчезнуть.

Ответ 11

Если, например, вы используете строки вместо символов, вы можете сделать что-то вроде этого:

    //a is a string of length 1
    string a;
    //b is the char in which we'll put the char stored in a
    char b;
    bool isInitialized(){
      if(a.length() != NULL){
        b = a[0];
        return true;
      }else return false;
    }

Ответ 12

Вы можете сослаться на переменную в утверждении и затем построить с -fsanitize=address:

void foo (int32_t& i) {
    // Assertion will trigger address sanitizer if not initialized:
    assert(static_cast<int64_t>(i) != INT64_MAX);
}

Это приведет к надежному аварийному завершению программы с трассировкой стека (в отличие от неопределенного поведения).