Это статическое поле класса используется до того, как оно было создано?

Итак, я экспериментировал со статическими полями классов (особенно с константными) и занялся… этим:

#include <iostream>
#include <conio.h>

class Test {
public:
    Test() { std::cout << "Constructing (Default CTOR)\n"; }
    Test(int f) { std::cout << "Constructing (Int arg CTOR)\n"; }

    void method() const { std::cout << "Already constructed and being used\n"; }
};

class Stack {
public:
    // static const Test what{ 5 }; // - "element of type "const Test" can not have an initializer inside of a class"
    // const Test ok{ 5 }; // now it can (?)

    static const Test what;

    Stack() {
        what.method();
    }

    // Stack() : what{5} {} // can't do that because "what" will be dependent on object creation (which is not how static class fields roll)
};

Stack obj;

const Test Stack::what{};

int main()
{
    _getch();
    return 0;
}

Выход:

Выход

По-видимому, static const Test what в Stack используется до того, как он был фактически создан (?).

После этого я провел еще один тест:

#include <iostream>
#include <conio.h>

class Test {
public:
    int data;

    Test() { std::cout << "CONSTRUCTING (Default CTOR)\n"; } // notice, value-initialization of 'data' has been removed
    Test(int f) : data{ f } { std::cout << "CONSTRUCTING (Int arg CTOR)\n"; }

    void method() const { std::cout << "ALREADY CONSTRUCTED AND BEING USED :)\n" << data << std::endl; }
};

class Stack {
public:
    static const Test what;

    Stack() {
        what.method();
    }
};

Stack obj;

const Test Stack::what{ 5 };

int main()
{
    obj.what.method();

    _getch();
    return 0;
}

В этом коде я надеялся увидеть какую-то ошибку, но результат в итоге выглядел так:

Выход 2

У меня есть некоторые предположения о том, что здесь происходит, но я не уверен, что они правильные. Так что, если они есть, пожалуйста, поправьте меня.

Вот мои предположения:

По сути, статические переменные создаются в самом начале программы (и инициализируются значениями) и удаляются в самом конце программы (когда вы на самом деле закрываете свой.exe). В моих примерах у меня есть статическая константа what в классе Stack и я думаю, что он создается в начале моей программы, инициализированной значением. Вот почему его data поле установлено в 0, и мы можем использовать его методы. Но я не думаю, что это правильно, потому что это вывело бы Constructing (Default CTOR) в консоль. Так что я вроде застрял там...

Я также не могу понять, почему закомментированные строки в моем первом примере являются незаконными. Какие правила статических / константных полей класса они точно нарушают?

Если у вас есть идеи о том, что происходит в моих примерах, пожалуйста, объясните это.

Спасибо за внимание.

1 ответ

Решение

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

Так obj всегда строится раньше what, Есть ограниченные вещи, которые можно сделать с объектами, которые имеют конструктор, но до вызова конструктора; и вызов функции-члена не является одним из них (C++14 [basic.life]/5.2). Итак, вызов what.method() в Stackконструктор вызывает неопределенное поведение.

Другие вопросы по тегам