URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 1422
[ Назад ]

Исходное сообщение
"C++ - Вопрос на засыпку"

Отправлено Bizon , 22-Фев-03 15:24 
Статический член класса обнуляется при создании или нет????

Содержание

Сообщения в этом обсуждении
"RE: C++ - Вопрос на засыпку"
Отправлено sas , 23-Фев-03 12:58 
Я бы сказал, что да. Примитивные типы = 0 а  объекты своими конструкторами

В принципе я предпочитаю инициализировать их явно :)

Успехов
--- sas


"RE: C++ - Вопрос на засыпку"
Отправлено Bizon , 24-Фев-03 14:09 
>Я бы сказал, что да. Примитивные типы = 0 а  объекты
>своими конструкторами
>
>В принципе я предпочитаю инициализировать их явно :)
>
>Успехов
>--- sas


Так ты бы сказал или оно так и есть???
если б стат член инициализировался нулём можно было бы не инециализировать его явно а в конструкторе проверять - если 0 - инициализируем если не ноль то ничего не делаем


"RE: C++ - Вопрос на засыпку"
Отправлено sas , 24-Фев-03 18:13 
>>Я бы сказал, что да. Примитивные типы = 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


"RE: C++ - Вопрос на засыпку"
Отправлено Bilbo , 26-Фев-03 17:23 
>Статический член класса обнуляется при создании или нет????

Нет.


"RE: C++ - Вопрос на засыпку"
Отправлено tch , 27-Фев-03 21:00 
>>Статический член класса обнуляется при создании или нет????
>
>Нет.

Зависит от компилятора ;-)
Некоторые компиляторы обнуляю объект при создание, некоторые нет.
Поэтому полагаться на это ни в коем случае не стоит и делать ручками.



"RE: C++ - Вопрос на засыпку"
Отправлено sas , 28-Фев-03 05:32 
>>>Статический член класса обнуляется при создании или нет????
>>
>>Нет.
>
>Зависит от компилятора ;-)
>Некоторые компиляторы обнуляю объект при создание, некоторые нет.
>Поэтому полагаться на это ни в коем случае не стоит и делать
>ручками.

Господа вы оба не правы: согласно стадарту ,   так называемые нелокальные статические объекты инициализируются 0 по умолчанию.  Если компилятор этого не делает
, то он не совместим со стандартом.

Кстати точно так  и в Си статические переменные инициализируются компилятором в 0
нулем.

Но даже в этом случае рекомендуется инициализировать явно . Посмотрите мой предидущий пост вариант №3.

Успехов
--- sas


"RE: C++ - Вопрос на засыпку"
Отправлено tch , 28-Фев-03 15:06 
А никто и не говорит о стандарте :-)
Это суровая правда жизни.

Мало я видел компиляторов АБСОЛЮТНО совместимых со стандартом ;-)

Опять же плюс- код по вожности должен быть самодокументируемым.


"RE: C++ - Вопрос на засыпку"
Отправлено romanSA , 28-Фев-03 15:59 
Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не могут НЕЯВНО инициализироваться в конструкторе.
Буду очень признателен, если Вы укажите хотя бы ОДИН компиллятор С++ в котором это не так (чтобы, не дай бог, случайно им не воспользоваться ;) ).
Поведение статических членов класса в С++ аналогично поведению статических переменных в функциях языка С.

P.S. Уважаемый sas, а если у меня нелокальный статический объект - это переменная какого-нибудь класса?
Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?


"RE: C++ - Вопрос на засыпку"
Отправлено tch , 28-Фев-03 17:20 
>Уважаемый tch, статические члены класса принадлежат ВСЕМ объектам данного класса и не
>могут НЕЯВНО инициализироваться в конструкторе.

Буду признателен, если Вы мне укажете где я утверждал обратное :-)
Тоже мне просветили.

Я говорю о том, что если яно не инициализировать (=Smth) то совсем не факт, что он будет обнулен (проблема может быть актуальна для старых/экзотических компиляторов).

> а если у меня нелокальный статический объект - это переменная какого-нибудь класса?
Каким же это "нулём" будет компиллятор её инициализировать по-умолчанию?

Гипотетически должен быть вызван конструктор по умолчанию.



"RE: C++ - Вопрос на засыпку"
Отправлено sas , 01-Мрт-03 05:14 
>Уважаемый 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


"RE: C++ - Вопрос на засыпку"
Отправлено sas , 01-Мрт-03 05:25 
>>Уважаемый 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 // а не мусор

:(



"RE: C++ - Вопрос на засыпку"
Отправлено romanSA , 03-Мрт-03 11:18 
Уважаемый sas!
Всё, что Вы пишете, безусловно правильно.
Только не надо забывать, что далеко не всегда компиллятор создаст конструктор по-умолчанию, а точнее - создаст если только Вы не создали сами хотя бы один конструктор.
Вот конструктор копирования - создаст всегда (если Вы сами об этом не позаботились).

P.S. Это не критика ;)
Просто хочется чтобы ответ был по-возможности полным, тем более, что это в данном случае не сложно.

P.P.S. И того: статические члены класса по-умолчанию инициализируются
- нулём для простых типов
- конструктором по-умолчанию, если он есть, для классов и структур
- если конструктор по-умолчанию не задан (или не может быть создан компиллятором), то нужно явно инициализировать эти члены.



"RE: C++ - Вопрос на засыпку"
Отправлено sas , 03-Мрт-03 15:18 
>Уважаемый 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


"RE: C++ - Вопрос на засыпку"
Отправлено SnaiL , 13-Май-03 18:03 

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

"RE: C++ - Вопрос на засыпку"
Отправлено sas , 14-Май-03 01:25 
>
>Если у вас есть статический член класса и он явно не проинециализирован
>и имеется опасность использования неинициализированной переменной (этого статического члена)
>тогда компилятор автоматически его проинициализирует нулевым значением. Если же нет, то этот
>член не будет инициализирован.

Уважаемый SnaiL

Как и когда именно происходит инициализация зависит от компилятора
Это может происходить как перед первым испльзованием/обращением так и даже перед входом в main.
Для программиста на С++ эта разница значения не имеет

Спасибо
--- sas