Статический член класса обнуляется при создании или нет????
Я бы сказал, что да. Примитивные типы = 0 а объекты своими конструкторамиВ принципе я предпочитаю инициализировать их явно :)
Успехов
--- sas
>Я бы сказал, что да. Примитивные типы = 0 а объекты
>своими конструкторами
>
>В принципе я предпочитаю инициализировать их явно :)
>
>Успехов
>--- sas
Так ты бы сказал или оно так и есть???
если б стат член инициализировался нулём можно было бы не инециализировать его явно а в конструкторе проверять - если 0 - инициализируем если не ноль то ничего не делаем
>>Я бы сказал, что да. Примитивные типы = 0 а объекты
>>своими конструкторами
>>
>>В принципе я предпочитаю инициализировать их явно :)
>>
>>Успехов
>>--- sas
>
>
>Так ты бы сказал или оно так и есть???
>если б стат член инициализировался нулём можно было бы не инециализировать его
>явно а в конструкторе проверять - если 0 - инициализируем если
>не ноль то ничего не делаемУ вас совершенно неправильная трактовка ответа::
Рассмотрим несколько примеров используя 2 файла ttt.hh и ttt.cxx
с ошибками разного типа и без нихВариант 1:
static члены объявлены но не определены и не инициализированны
(хотя бы один)// --- ttt.hh ---------------------------------------
#ifndef __ttt_hh__
#define __ttt_hh__#include <iostream>
using std::cout;
using std::endl;class Demo {
// Только объявлены
static int i_;
static bool b_;public:
void print()
{
cout << "i_ = " << i_ << "\n"
<< "b_ = " << b_ << endl;
}
};
// --- ttt.cxx ---------------------------------------------
#include "ttt.hh"// Нельзя не инициализировать static члены //
int main()
{
Demo d;
d.print();
return 0;
}Этот пример не будет слинкован из-за Uninitialized static members
Те мы объявили но не определили :(==============================================
Вариант 2
Пытаемся инициализировать static член в конструкторе и .... не получается... Почему? А потому что статические члены должны быть инициализированы до этого. На самом деле они инициализируются даже до начала выполнения main
// --- ttt.hh ---------------------------------------
#ifndef __ttt_hh__
#define __ttt_hh__#include <iostream>
using std::cout;
using std::endl;class Demo {
// Только объявлены
static int i_;
static bool b_;public:
Demo() { i_ = 123; }
void print()
{
cout << "i_ = " << i_ << "\n"
<< "b_ = " << b_ << endl;
}
};
// --- ttt.cxx ---------------------------------------------
#include "ttt.hh"// Нельзя не инициализировать static члены //
int main()
{
Demo d;
d.print();
return 0;
}============================================
Вариант 3
Инициализируем static значениями по умолчанию
// --- ttt.hh ---------------------------------------
#ifndef __ttt_hh__
#define __ttt_hh__#include <iostream>
using std::cout;
using std::endl;class Demo {
// Только объявлены
static int i_;
static bool b_;public:
void print()
{
cout << "i_ = " << i_ << "\n"
<< "b_ = " << b_ << endl;
}
};
// --- ttt.cxx ---------------------------------------------
#include "ttt.hh"int Demo::i_;
bool Demo::b_;int main()
{
Demo d;
d.print();
return 0;
}После компиляции и выполнения получим что
i_ = 0; // как и для обычных static переменных
b_ = false; // false == 0 не правда ли?=========================================
Вариант 4
Определим static а ПОТОМ
присвоим другое значение static члену в конструкторе... Будет работать// --- ttt.hh ---------------------------------------
#ifndef __ttt_hh__
#define __ttt_hh__#include <iostream>
using std::cout;
using std::endl;class Demo {
// Только объявлены
static int i_;
static bool b_;public:
Demo() { i_ = 123; }
void print()
{
cout << "i_ = " << i_ << "\n"
<< "b_ = " << b_ << endl;
}
};
// --- ttt.cxx ---------------------------------------------
#include "ttt.hh"int Demo::i_;
bool Demo::b_;int main()
{
Demo d;
d.print();
return 0;
}После компиляции и выполнения получим что
i_ = 123; // должно быть так
b_ = false; // false == 0 не правда ли?=============================================
Вариант 5
Добавим комплексные статические члены.
// --- ttt.hh ---------------------------------------
#ifndef __ttt_hh__
#define __ttt_hh__#include <iostream>
using std::cout;
using std::endl;class Class1 {
public:
void print() { cout << "Class1"; }
};class Class2 {
std::string s_;
public:
Class2( const char* s ) : s_( s ) {}
void print() { cout << "Class2" << endl; }
private:
Class2() {}
};class Class3 {
public:
void print() { cout << "Class3" << endl; }
private:
Class3( const Class3& other ) {}
void operator=( const Class3& other ) {}
};class Demo {
// Definitions...
static int i_;
static bool b_;static Class1 c1_;
static Class2 c3_;
static Class3 c3_;public:
void print()
{
cout << "i_ = " << i_ << "\n"
<< "b_ = " << b_ << endl;
c1_.print();
c2_.print();
c3_.print();
}
};// --- ttt.cxx ---------------------------------------------
#include "ttt.hh"int Demo::i_;
bool Demo::b_;// Если не определим static член (хотя-бы один) программа не
// слинкуется
Class1 Demo::c1_; // вызывается конструктор по
//умолчанию сгенеренный компиляторомClass2 Demo::c2_; // До тех пор пока не сделаем наш
// конструктор по умолчанию public или не
// уберем его вообще не сможем скомпилироватьClass3 Demo::c3_; // Если копиконструктор и оператор присваивания не
// public мы не можем использовать
// сгенеренный компилятором конструктор.
//
// Надо делать public конструктор по умолчанию!!!// !!! Кроме того если класс имеет какие то другие
// конструкторы, то мы можем их использовать явно
//
// В этом случае наш конструктор по умолчанию может быть
// private/protected и мы не зависим от копи конструкторв и
// операторов присваивания :)
//
// Н-р: Class2 Demo::c2_( "SSSSSSSSSSSS" );
//int main()
{
Demo d;
d.print();
return 0;
}Ну вот вроде бы и все
ВАЖНОЕ ЗАМЕЧАНИЕ: Код не был скомпилирован!!! Могут быть ошибки
КОД ПРЕДНАЗНАЧЕН ДЛЯ ПОЯСНЕНИЯ!!!Успехов в изучении С++
--- sas
>Статический член класса обнуляется при создании или нет????Нет.
>>Статический член класса обнуляется при создании или нет????
>
>Нет.Зависит от компилятора ;-)
Некоторые компиляторы обнуляю объект при создание, некоторые нет.
Поэтому полагаться на это ни в коем случае не стоит и делать ручками.
>>>Статический член класса обнуляется при создании или нет????
>>
>>Нет.
>
>Зависит от компилятора ;-)
>Некоторые компиляторы обнуляю объект при создание, некоторые нет.
>Поэтому полагаться на это ни в коем случае не стоит и делать
>ручками.Господа вы оба не правы: согласно стадарту , так называемые нелокальные статические объекты инициализируются 0 по умолчанию. Если компилятор этого не делает
, то он не совместим со стандартом.Кстати точно так и в Си статические переменные инициализируются компилятором в 0
нулем.Но даже в этом случае рекомендуется инициализировать явно . Посмотрите мой предидущий пост вариант №3.
Успехов
--- sas
А никто и не говорит о стандарте :-)
Это суровая правда жизни.Мало я видел компиляторов АБСОЛЮТНО совместимых со стандартом ;-)
Опять же плюс- код по вожности должен быть самодокументируемым.
Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не могут НЕЯВНО инициализироваться в конструкторе.
Буду очень признателен, если Вы укажите хотя бы ОДИН компиллятор С++ в котором это не так (чтобы, не дай бог, случайно им не воспользоваться ;) ).
Поведение статических членов класса в С++ аналогично поведению статических переменных в функциях языка С.P.S. Уважаемый sas, а если у меня нелокальный статический объект - это переменная какого-нибудь класса?
Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?
>Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не
>могут НЕЯВНО инициализироваться в конструкторе.Буду признателен, если Вы мне укажете где я утверждал обратное :-)
Тоже мне просветили.Я говорю о том, что если яно не инициализировать (=Smth) то совсем не факт, что он будет обнулен (проблема может быть актуальна для старых/экзотических компиляторов).
> а если у меня нелокальный статический объект - это переменная какого-нибудь класса?
Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?Гипотетически должен быть вызван конструктор по умолчанию.
>Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не
>могут НЕЯВНО инициализироваться в конструкторе.
>Буду очень признателен, если Вы укажите хотя бы ОДИН компиллятор С++ в
>котором это не так (чтобы, не дай бог, случайно им не
>воспользоваться ;) ).
>Поведение статических членов класса в С++ аналогично поведению статических переменных в функциях
>языка С.
>
>P.S. Уважаемый sas, а если у меня нелокальный статический объект - это
>переменная какого-нибудь класса?
>Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?
Уважаемый romanSA! :)Я говорю об инициализции статических перменных (статическая) которая производится ДО ТОГО как происходит любая другая инициализация во время выполнения (динамическая).
<<
Variables with storage class static (3.5) that are not initialized are guaranteed to start off as 0 converted to the appropriate type. So are members of static class objects. The initial values of automatic and register variables that are not initialized are undefined.
>>В своем первом посте и далее я ответил что примитивные типы инициализируются 0 а объекты - конструктороми (по умолчанию, сгенерированные компилятором или любые другие). Конструкторы упомянуты потому что, как я уверен, Вы знаете, что без них ни один экземпляр класса (объект) не может быть создан :) (см мой пост 2 в текущем обсуждении последнийй пример)
Если Вы не написали свой конструктор и используете статический объект вашего класса то используется конструктор сгенерированный компилятором. В случае сгенерированного конструктора все члены примитивного типа инициализируются согласно обычным правилам: все статические - 0 а обычные - мусором. Посмотрите мой второй пост (последний пример).
Кстати тоже самое относится и если Вы написали конструктор в котором инициализируете НЕ все члены:
#include <iostream>
struct C {
int a_;
int b_;
int c_;
static int d_;C() : a_( 1 ), b_( 2 ) {}
}int C::d_ = 123;
static C static_c;
int main()
{
std::cout << "static_c.a_=" << static_c.a_
<< "\nstatic_c.b_=" << static_c.b_
<< "\nstatic_c.c_=" << static_c.c_
<< "\nstatic_c.a_=" << static_c.a_ << std::endl;
return 0;
}Результаты (должны быть!!! Но код не был скомпилирован):
static_c.a_ = 1; // конструктор
static_c.b_ = 2; // ----"------
static_c.c_ = 345987; // мусор
static_c.d_ = 123; // как мы и хотелиСлово "нелокальные" - это буквальный перевод из стандарта:
3.6.2 - Initialization of non-local objects
Вывод: Как говорит мой тесть: "Батенька, читайте матчасть!" (предидущие посты)
Успехов
---sas
>>Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не
>>могут НЕЯВНО инициализироваться в конструкторе.
>>Буду очень признателен, если Вы укажите хотя бы ОДИН компиллятор С++ в
>>котором это не так (чтобы, не дай бог, случайно им не
>>воспользоваться ;) ).
>>Поведение статических членов класса в С++ аналогично поведению статических переменных в функциях
>>языка С.
>>
>>P.S. Уважаемый sas, а если у меня нелокальный статический объект - это
>>переменная какого-нибудь класса?
>>Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?
>
>
>Уважаемый romanSA! :)
>
>Я говорю об инициализции статических перменных (статическая) которая производится ДО ТОГО
>как происходит любая другая инициализация во время выполнения (динамическая).
>
><<
>Variables with storage class static (3.5) that are not initialized are guaranteed
>to start off as 0 converted to the appropriate type. So
>are members of static class objects. The initial values of automatic
>and register variables that are not initialized are undefined.
>>>
>
>В своем первом посте и далее я ответил что примитивные типы инициализируются
>0 а объекты - конструктороми (по умолчанию, сгенерированные компилятором или любые
>другие). Конструкторы упомянуты потому что, как я уверен, Вы знаете, что
>без них ни один экземпляр класса (объект) не может быть создан
> :) (см мой пост 2 в текущем обсуждении последнийй пример)
>
>
>Если Вы не написали свой конструктор и используете статический объект вашего
>класса то используется конструктор сгенерированный компилятором. В случае сгенерированного конструктора
>все члены примитивного типа инициализируются согласно обычным правилам: все статические -
>0 а обычные - мусором. Посмотрите мой второй пост (последний пример).
>
>
>Кстати тоже самое относится и если Вы написали конструктор в котором инициализируете
>НЕ все члены:
>
>#include <iostream>
>
>struct C {
> int a_;
> int b_;
> int c_;
> static int d_;
>
> C() : a_( 1 ), b_( 2 ) {}
>}
>
>int C::d_ = 123;
>
>static C static_c;
>
>int main()
>{
> std::cout << "static_c.a_=" << static_c.a_
> << "\nstatic_c.b_=" << static_c.b_
> << "\nstatic_c.c_=" << static_c.c_
> << "\nstatic_c.a_=" << static_c.a_ << std::endl;
> return 0;
>}
>
>Результаты (должны быть!!! Но код не был скомпилирован):
>
>static_c.a_ = 1;
> // конструктор
>static_c.b_ = 2;
> // ----"------
>static_c.c_ = 345987; // мусор
>static_c.d_ = 123; // как
>мы и хотели
>
>Слово "нелокальные" - это буквальный перевод из стандарта:
>
>3.6.2 - Initialization of non-local objects
>
>Вывод: Как говорит мой тесть: "Батенька, читайте матчасть!" (предидущие посты)
>
>Успехов
>---sasПрошу прощения спорол чушь в предидущем посте по поводу неинициализированного
члена:ОН БУДЕТ 0 также. Конструктор сгенерированный компилятором и правда так работает НО не в случае статического объекта. Cм предидущий пост
<<
Variables with storage class static (3.5) that are not initialized are guaranteed to start off as 0 converted to the appropriate type. So are members of static class objects. The initial values of automatic and register variables that are not initialized are undefined.
>>Т.Е.
static_c.c_ = 0 // а не мусор
:(
Уважаемый sas!
Всё, что Вы пишете, безусловно правильно.
Только не надо забывать, что далеко не всегда компиллятор создаст конструктор по-умолчанию, а точнее - создаст если только Вы не создали сами хотя бы один конструктор.
Вот конструктор копирования - создаст всегда (если Вы сами об этом не позаботились).P.S. Это не критика ;)
Просто хочется чтобы ответ был по-возможности полным, тем более, что это в данном случае не сложно.P.P.S. И того: статические члены класса по-умолчанию инициализируются
- нулём для простых типов
- конструктором по-умолчанию, если он есть, для классов и структур
- если конструктор по-умолчанию не задан (или не может быть создан компиллятором), то нужно явно инициализировать эти члены.
>Уважаемый sas!Уважаемый romanSA!
:)>Всё, что Вы пишете, безусловно правильно.
>Только не надо забывать, что далеко не всегда компиллятор создаст конструктор по-умолчанию,
>а точнее - создаст если только Вы не создали сами хотя
>бы один конструктор.
>Вот конструктор копирования - создаст всегда (если Вы сами об этом не
>позаботились).
>
>P.S. Это не критика ;)
>Просто хочется чтобы ответ был по-возможности полным, тем более, что это в
>данном случае не сложно.
>
К сожалению и я и Вы немного отошли от темы: Вопрос был про инициализацию статических переменных по умолчанию. Да, Вы тоже правильно сказали по поводу конструктора поумолчанию сгенеренного компилятором (кстати говоря я нигде другого и не говорил: Код который я приводил в качестве примера был написан для иллюстрации что все работает и при статических членах класса а не для иллюстрации создания объектов.конструктор Сlass2::Class2( const char*) был добавлен для иллюстрации возможности явной инициализации и единственное что я не сделал - это я его не закомментировал :( Sorry
)КОНСТРУКТОРЫ были упомянуты потому, что без них объекта не создать :) Так что они в данном случае только вспомогательный материал
НО еще раз повторяю, что
ВОПРОС был про инициализацию статических переменных (простых и не очень) ПО УМОЛЧАНИЮ
>P.P.S. И того: статические члены класса по-умолчанию инициализируются
>- нулём для простых типов
>- конструктором по-умолчанию, если он есть, для классов и структурА теперь собственно ответ:
К сожалению я так и не сумел объяснить что же творится когда переменная (не важно какая простая или комплексная) объявлена статической (cм мои предидущие посты и особенно Сообщение от sas on 01-Мрт-03, 05:14 (MSK)):
На этапе СТАТИЧЕСКОЙ инициализации которая происходит ДО первого использования/создания переменной вся область памяти где явно не инициализированная переменная (ее данные или члены) хранится обнуляется (что-то вроде memset( &var, 0, sizeof( var ) );
Это объяснение - физический смысл того что делается а не алгоритм
Это означает что ВСЯ область памяти где находятся эти переменные == 0000000...00000000000000000000000
(по байтикам) :)<<
Variables with storage class static (3.5) that are not initialized are guaranteed to start off as 0 converted to the appropriate type. So are members of static class objects. The initial values of automatic and register variables that are not initialized are undefined.
>>Ключевая фраза в "буквальном переводе":
<<
Статические переменные, которые не проиницилизированны явно гарантированно будут равны 0 приведенному к типу этой переменной. Это же относится к членам статических объектов классов.
Начальные значения автоматических и регистровых переменных которые не проинициализированны явно не определены (мусор)
>>(см мой пример со статическим bool членом класса, там это (приведение 0 к типу) явно показано)
Все точно также как и я, и ВЫ, упоминали: как и в обычном (не плюс плюс) CиПосле этого начинается ДИНАМИЧЕСКАЯ инициализация Во время которой и вызывается нужный конструктор
(опять же сгенеренный или определенный (кстати если есть хотя бы один определенный конструктор сигнатура которого не соответствует конструктору по умолчанию и конструктор по умолчанию не определен и пользователь пытается сделать "Class2 Demo::c2_;" Компилятор откажется с таким кодом работать и пользователь ничего не скомпилирует. :) Ваше замечание :)) ))Все вышеизложенное показывает, что ВСЕ статические переменные (явно не инициализированные) == 0 по умолчанию, но для объектов классов на этапе динамической инициализации ВСЕГДА вызывается конструктор по умолчанию (если программист не использует явной инициализации с каким либо другим конструктором)
Опять же иначе объект не создадимПродемонстрируем что по умолчанию члены класса == 0
Пример
struct Demo {
int a_;
Demo() { std::cout << "Demo::Demo();" << std:endl; }
void print() { std::cout << "a_=" << a_ << std::endl; }
};Как Вы видите я создал конструктор по умолчанию который НИЧЕГО не делает (эмуляция сгенеренного - по правилам если объект типа Demo не статический, то Demo::a_ == мусор, т.к. a_ - не статический член)
Я его (конструктор) сделал для демонстрации что он вызывается
Теперь
static Demo staic_demo; // Объявляем но явно не инициализируем
int main()
{
static_demo.print();return 0;
}Результаты:
Demo::Demo();
a_=0; // из этапа статической инициализации>- если конструктор по-умолчанию не задан (или не может быть создан компиллятором),
>то нужно явно инициализировать эти члены.Из предидущего примера видно, что конструктор НЕ ИНИЦИАЛИЗИРУЕТ а ПЕРЕОПРЕДЕЛЯЕТ значения!!!
Кстати Ваша фраза о явной инициализации тут вообще не нужна, т.к.
struct Demo { static int a_; } // только объявили
int Demo::a_; // определили но ЯВНО не проинициализировали
Если int Demo::a_; (или int Demo:a_ = 123;) НЕТ ни в одном объектнике то и слинковать невозможно!!!
( Извините, но так как мы разговариваем об инициализации по умолчанию, я не буду рассказывать здесь о проблемах с порядком определения статических переменных, зависящих от друг друга, в разных translation units хотя это и близкая проблема, просто потому, что ВОПРОС другой. Если Вас или кого еще это заинтерисует то предлагаю открыть новое обсуждение)
==============================
ВЫВОД: По умолчанию вся статика явно не инициализированная == 0 а потом Конструктор для Объектов, который присваивает новые значения перезаписывая 0 ( если код для этого в конструкторе есть) ==============================:)
Ну вот вроде бы и все
С уважением
--- sas
Если у вас есть статический член класса и он явно не проинециализирован и имеется опасность использования неинициализированной переменной (этого статического члена)
тогда компилятор автоматически его проинициализирует нулевым значением. Если же нет, то этот член не будет инициализирован.
>
>Если у вас есть статический член класса и он явно не проинециализирован
>и имеется опасность использования неинициализированной переменной (этого статического члена)
>тогда компилятор автоматически его проинициализирует нулевым значением. Если же нет, то этот
>член не будет инициализирован.Уважаемый SnaiL
Как и когда именно происходит инициализация зависит от компилятора
Это может происходить как перед первым испльзованием/обращением так и даже перед входом в main.
Для программиста на С++ эта разница значения не имеетСпасибо
--- sas