Default variable value

后端 未结 9 1478
生来不讨喜
生来不讨喜 2020-11-22 13:21

If I don\'t assign a value to a variable when I declare it, does it default to zero or just whatever was previously in the memory?

e.g.

float x;


        
相关标签:
9条回答
  • 2020-11-22 13:55

    Since the current top-answer was written in 2011 and only refers to C++03, I am providing an updated answer to keep into account changes made after C++11. Note that I am stripping any information that only held true until C++03 or C++11 and unnecessary notes that can be seen in the original sources. I am quoting the original specifications as much as I can, in order to avoid unnecessary reformulation which may lead to inexact information. Please consult the original sources I am providing if you are interested in diving deeper into a certain topic. Also, be warned that I am mainly focusing on rules regarding * Default initialization * Undefined behavior * Zero-initialization Since it seems to me that these are the most important aspects needed to understand how a variable behaves "by default", as the question is asking.

    Default initialization is performed in some cases:

    1. when a variable with automatic, static, or thread-local storage duration is declared with no initializer;
    2. when an object with dynamic storage duration is created by a new-expression with no initializer;
    3. when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.

    and the effects of this default initialization are:

    • if T is a non-POD (until C++11) class type, the constructors are considered and subjected to overload resolution against the empty argument list. The constructor selected (which is one of the default constructors) is called to provide the initial value for the new object;

    • if T is an array type, every element of the array is default-initialized;

    • otherwise, nothing is done: the objects with automatic storage duration (and their subobjects) are initialized to indeterminate values.

    Meaning that if the uninitialized variable is a local (say, an int only present in a function's scope), its value is indeterminate (undefined behavior). cppreference strongly discourages the usage of uninitialized variables.

    As a side note, even though most modern compilers will issue an error (at compile-time) if they detect that an uninitialized variable is being used, they usually fail to do so in cases were you are "tricking" them to think you may be initializing the variable somehow, such as in:

    int main()
    {
        int myVariable;
        myFunction(myVariable);  // does not change the variable
        cout << myVariable << endl;  // compilers might think it is now initialized
    }
    

    Starting from C++14, the following holds (note that std::byte was introduced with C++17):

    Use of an indeterminate value obtained by default-initializing a non-class variable of any type is undefined behavior (in particular, it may be a trap representation), except in the following cases:

    • if an indeterminate value of type unsigned char or std::byte is assigned to another variable of type (possibly cv-qualified) unsigned char or std::byte (the value of the variable becomes indeterminate, but the behavior is not undefined);

    • if an indeterminate value of type unsigned char or std::byte is used to initialize another variable of type (possibly cv-qualified) unsigned char or std::byte;

    • if an indeterminate value of type unsigned char or std::byte (since C++17) results from

      • the second or third operand of a conditional expression,
      • the right operand of the comma operator,
      • the operand of a cast or conversion to (possibly cv-qualified) unsigned char or std::byte,
      • a discarded-value expression.

    Additional details about the default initialization of variables and their behavior can be found here.

    To dive deeper into indeterminate values, in 2014 the following changes were made (as Shafik Yaghmour pointed out here with additional useful resources):

    If no initializer is specified for an object, the object is default-initialized; if no initialization is performed, an object with automatic or dynamic storage duration has indeterminate value. [Note: Objects with static or thread storage duration are zero-initialized]

    to:

    If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. [Note: Objects with static or thread storage duration are zero-initialized] If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:

    • If an indeterminate value of unsigned narrow character type is produced by the evaluation of:

      • the second or third operand of a conditional expression (5.16 [expr.cond]),

      • the right operand of a comma,

      • the operand of a cast or conversion to an unsigned narrow character type, or

      • a discarded-value expression,

        then the result of the operation is an indeterminate value.

    • If an indeterminate value of unsigned narrow character type is produced by the evaluation of the right operand of a simple assignment operator whose first operand is an lvalue of unsigned narrow character type, an indeterminate value replaces the value of the object referred to by the left operand.

    • If an indeterminate value of unsigned narrow character type (3.9.1 [basic.fundamental]) is produced by the evaluation of the initialization expression when initializing an object of unsigned narrow character type, that object is initialized to an indeterminate value.

    Finally, there is the subject of zero-initialization which is performed in the following situations:

    1. For every named variable with static or thread-local storage duration that is not subject to constant initialization (since C++14), before any other initialization.

    2. As part of value-initialization sequence for non-class types and for members of value-initialized class types that have no constructors, including value initialization of elements of aggregates for which no initializers are provided.

    3. When an array of any character type is initialized with a string literal that is too short, the remainder of the array is zero-initialized.

    The effects of zero initialization are:

    • If T is a scalar type, the object's initial value is the integral constant zero explicitly converted to T.

    • If T is an non-union class type, all base classes and non-static data members are zero-initialized, and all padding is initialized to zero bits. The constructors, if any, are ignored.

    • If T is a union type, the first non-static named data member is zero-initialized and all padding is initialized to zero bits.

    • If T is array type, each element is zero-initialized

    • If T is reference type, nothing is done.

    Following are some examples:

    #include <iostream>
    #include <string>
    
    struct Coordinates {
        float x, y;
    };
    
    class WithDefaultConstructor {
        std::string s;
    }
    
    class WithCustomConstructor {
        int a, b;
    
    public:
        WithCustomConstructor() : a(2) {}
    }
    
    int main()
    {
        int a;    // Indeterminate value (non-class)
    
        int& b;   // Error
    
        std::string myString;    // Zero-initialized to indeterminate value
                                 // but then default-initialized to ""
                                 // (class, calls default constructor)
    
        double coordsArray[2];   // Both will be 0.0 (zero-initialization)
    
        Coordinates* pCoords;    // Zero-initialized to nullptr
    
        Coordinates coords = Coordinates();
    
        // x: 0.0
        // y: 0.0
        std::cout << "x: " << coords.x << '\n'
            "y: " << coords.y << std::endl;
    
        std::cout << a.a << a.b << a.c << '\n';
    
        WithDefaultConstructor wdc;    // Since no constructor is provided,
                                       // calls the default constructor
    
        WithCustomConstructor wcs;     // Calls the provided constructor
                                       // a is initialized, while b is
                                       // default-initialized to an indeterminate value
    }
    
    0 讨论(0)
  • 2020-11-22 13:56

    C++ does not instantiate variables. The value of x is whatever happened to be in the memory at the time. Never assume anything about its initial value.

    0 讨论(0)
  • 2020-11-22 13:59

    It depends. If this is a local variable (an object with automatic storage duration) it will be uninitialized, if it is a global variable (an object with static storage duration) it will be zero initialized. Check also this answer.

    0 讨论(0)
提交回复
热议问题