Инициализация статического члена данных

Почему не происходит инициализация статического члена данных по умолчанию? В следующем примере

struct data_member
{
    data_member(){ cout << "data_member\n"; }
    ~data_member(){ cout << "~data_member\n"; }
};

struct Y
{
    static data_member m;
    Y(){ cout << "Y\n"; }
    ~Y(){ cout << "~Y\n"; }
};

Y y; //call constructor of Y 

но если мы удалим static спецификатор от data_member m он будет инициализирован по умолчанию.

struct data_member
{
    data_member(){ cout << "data_member\n"; }
    ~data_member(){ cout << "~data_member\n"; }
};

struct Y
{
    data_member m;
    Y(){ cout << "Y\n"; }
    ~Y(){ cout << "~Y\n"; }
};

Y y; //call Y() and data_member()

4 ответа

Решение

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

Следующее описание из проекта стандарта о static Переменные-члены должны объяснить, почему они не инициализируются по умолчанию в объявлении класса.

9.4.2 Статические данные членов

2 Объявление static член данных в своем определении класса не является определением и может иметь неполный тип, отличный от cv-qualified void, Определение для static элемент данных должен появиться в области имен, включающей определение класса члена. В определении в области именного пространства имя static член данных должен быть квалифицирован по имени класса с помощью оператора::.

static члены данных объявлены в class определение. Они должны быть определены (один раз) вне этого, как правило, в соответствующем cpp файл:

data_member Y::m;

Здесь вы увидите, как называется ctor по умолчанию.

struct Y
{
    static data_member m;
    Y(){ cout << "Y\n"; }
    ~Y(){ cout << "~Y\n"; }
};

Это только заявляет m, Поскольку все, что знает компилятор, Y::m определяется в другой единице перевода. Так как члены статических данных являются индивидуальными для каждого класса, вы должны иметь возможность объявлять их, не определяя их, или вы не сможете поместить определение класса в файл заголовка, не нарушив Правило единого определения при включении заголовка в разные переводческие единицы.

data_member Y::m;

Это определяет m и вызовет вызов конструктора.

Основной ответ: с учениками это похоже на функции. У нас есть декларации и определения. Вы "объявляете" их уровень существования @class, а "определение" производится конструктором. Со статическим членом его сложнее. Они не "связаны с экземпляром", и конструктор не будет "определять" их. Вы должны сделать это самостоятельно вне класса:

Type CLASS::member;

Кстати, это довольно плохая практика использовать статические элементы.

Вместо этого используйте статическую функцию:

class Foo{
public:
     Type &getMember(){
         static Type member;
         return member;
     }
};
Другие вопросы по тегам