web-dev-qa-db-fra.com

Vérifier si une variable est initialisée

On dirait que ce serait un doublon, mais peut-être que c'est tellement évident qu'on ne l'a pas demandé ...

Est-ce la bonne façon de vérifier si une variable (pas un pointeur) est initialisée dans une classe C++?

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;
};

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

    if ( ! mDecimal )
    {
        // define mDecimal.
    }
}
45
user542687

Il n'y a aucun moyen de vérifier si le contenu d'une variable est indéfini ou non. La meilleure chose à faire est d’attribuer une valeur signal/sentinelle (par exemple, dans le constructeur) pour indiquer qu’une autre initialisation devra être effectuée.

28
Alexander Gessler

Une variable non définie causera une erreur de compilation.

Ce que vous demandez, c'est de vérifier si c'est initialisé . Mais l’initialisation n’est qu’une valeur que vous devez choisir et attribuer dans le constructeur.

Par exemple:

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

Vous devez bien sûr initialiser une valeur par défaut qui aura une signification dans le contexte de votre logique.

20
littleadv

En fonction de vos applications (et particulièrement si vous utilisez déjà boost), vous voudrez peut-être vous intéresser à boost::optional .

(UPDATE: à partir de C++ 17, facultatif fait maintenant partie de la bibliothèque standard, comme std::optional )

Il possède la propriété que vous recherchez, permettant de savoir si l'emplacement contient réellement une valeur ou non. Par défaut, il est construit pour ne pas contenir de valeur et être évalué à false, mais s'il est évalué à true, vous pouvez le déréférencer et obtenir la valeur renvoyée.

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

Plus d'exemples se trouvent dans la documentation Boost .

14
HostileFork

Avec C++ 17, vous pouvez utiliser std::optional pour vérifier si une variable est initialisée:

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

Cela produira la sortie:

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

Pour utiliser std::optional dans le code que vous avez fourni, vous devez inclure l’en-tête <optional> standard et ajouter std::optional<...> aux déclarations de variable correspondantes:

#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.
    }
}
8
Elmar

Par défaut, non, vous ne pouvez pas savoir si une variable (ou un pointeur) a été initialisée ou non. Cependant, puisque tout le monde vous dit l'approche «facile» ou «normale», je vais vous donner une autre chose à laquelle réfléchir. Voici comment vous pourriez garder trace de quelque chose comme ça (non, personnellement, je ne le ferais jamais, mais vous avez peut-être des besoins différents de ceux que je suis).

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;
};
3
Chris Eberle

Avec C++ - 11, vous pouvez envisager de stocker la variable à l’aide de pointeurs intelligents. Considérez ce MVE où toString() comportement dépend de bar être initialisé ou non

#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();
    }
};

Utiliser ce code

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

produit la sortie

unset
42
2
Twonky

Il n'y a pas de moyen raisonnable de vérifier si une valeur a été initialisée.

Si vous voulez savoir si quelque chose a été initialisé, au lieu d'essayer de le vérifier, insérez du code dans le ou les constructeurs pour vous assurer qu'ils sont toujours initialisés et qu'ils sont terminés.

1
Jerry Coffin

Puisque MyClass est un type de classe POD, ces données membres non statiques auront des valeurs initiales indéterminées lorsque vous créez une instance non statique de MyClass, donc non, ce n'est pas un moyen valide de vérifier si elles ont été initialisées à une instance non spécifique -zéro valeur ... vous supposez fondamentalement qu'elles seront initialisées à zéro, ce qui ne sera pas le cas puisque vous ne les avez pas initialisées dans un constructeur.

Si vous souhaitez initialiser à zéro les membres de données non statiques de votre classe, il serait préférable de créer une liste d'initialisation et un constructeur de classe. Par exemple:

class MyClass
{
    void SomeMethod();

    char mCharacter;
    double mDecimal;

    public:
        MyClass();
};

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

La liste d'initialisation dans le constructeur ci-dessus valeur initialise vos membres de données à zéro. Vous pouvez maintenant correctement supposer que toutes les valeurs non nulles pour mCharacter et mDecimal doivent avoir été spécifiquement définies par vous ailleurs dans votre code et contenir des valeurs non nulles sur lesquelles vous pouvez agir correctement.

1
Jason

Si vous voulez savoir comment vérifier si les variables membres ont été initialisées, vous pouvez le faire en leur affectant des valeurs sentinelles dans le constructeur. Choisissez les valeurs sentinelles comme des valeurs qui ne se produiront jamais lors de l'utilisation normale de cette variable. Si une plage entière de variables est considérée comme valide, vous pouvez créer un booléen pour indiquer si elle a été initialisée.

#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.
    }
}
1
Praetorian

Vous pouvez référencer la variable dans une assertion, puis construire avec -fsanitize=address:

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

Cela provoquera un crash fiable du programme avec une trace de pile (par opposition à un comportement non défini).

0
sffc

Le langage C++ ne permet pas de vérifier si une variable est initialisée ou non (bien que les types de classe avec constructeurs soient automatiquement initialisés).

Au lieu de cela, vous devez fournir des constructeurs qui initialisent votre classe à un état valide. Les vérificateurs de code statiques (et éventuellement certains compilateurs) peuvent vous aider à trouver les variables manquantes dans les constructeurs. De cette façon, vous ne vous inquiétez pas (avez} _ d'être dans un état faux et les vérifications if de votre méthode peuvent disparaître complètement.

0
Mark B

Si, par exemple, vous utilisez des chaînes au lieu de caractères, vous pourrez peut-être faire quelque chose comme ceci:

    //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;
    }
0
Allan Lago