Модераторы: Daevaorn

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Инициализация в конструкторе класса, Пути решения 
:(
    Опции темы
VFaraon
  Дата 26.3.2007, 23:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 7
Регистрация: 5.12.2006
Где: Боярка, UA

Репутация: нет
Всего: нет



Вот читаю Р. Лафоре... Мне нравится. Очень много полезных мелочей описано. И попал я на такую информацию:

Код

...
class Counter
{
  private:
   unsigned int count;
  public:
   Counter() : count(0)
     { /*Пустое тело*/}
  void inc_count()
   {
 ......


И еще...

Цитата

... Вы, вероятно, ожидали, что это действие будет произведено в теле конструктора приблизительно следующим образом:
 
count()
   { count=0; }

  Такая форма записи не рекомендется, не смотря на то, что она не содержит ошибок. Инициализация в нашем примере происходит следующим образом:

count(): count(0)
 { }

.....

   Причины, по которым инициализация не проводится в теле конструктора достаточно сложны. Инициализация полей с помощью списка инициализации происходит до начала исполнения тела конструктора, что в некоторых ситуациях бывает важно. Так, например, список инициализации - это единственный способ задать начальные значения констант и ссылок.
.....


 "Такая форма записи не рекомендется" - Не мог бы ктото поподробней рассказать об этой ситуации?

"достаточно сложны" - И об этом... 


"Инициализация полей с помощью списка инициализации происходит до начала исполнения тела конструктора, что в некоторых ситуациях бывает важно" - Было бы оч хорошо, БОЛЬШЕ узнать об ЭТОМ механизме. Может ссылочку дадите или ктото сам попробует, а то уж больно интересный (для меня) вопрос smile



   
PM MAIL   Вверх
Daevaorn
Дата 26.3.2007, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 2155
Регистрация: 29.11.2004
Где: Москва

Репутация: 51
Всего: 70



Цитата(VFaraon @  27.3.2007,  00:19 Найти цитируемый пост)
 Не мог бы ктото поподробней рассказать об этой ситуации?

да. не рекомендуется. просто  по тому, что есть список инициализации
Цитата(VFaraon @  27.3.2007,  00:19 Найти цитируемый пост)
"достаточно сложны" - И об этом... 

это надо у автора спрашивать
Цитата(VFaraon @  27.3.2007,  00:19 Найти цитируемый пост)
"Инициализация полей с помощью списка инициализации происходит до начала исполнения тела конструктора, что в некоторых ситуациях бывает важно" - Было бы оч хорошо, БОЛЬШЕ узнать об ЭТОМ механизме. Может ссылочку дадите или ктото сам попробует, а то уж больно интересный (для меня) вопрос

чистая правда. компилятор может соптимизировать код инициализации, именно поэтому её и советуют использовать. Ну и наконец, ссылки члены класса могут буть инициализированы только в списке инициализации конструктора. Это по сути основное отличие.
PM MAIL WWW   Вверх
Earnest
Дата 27.3.2007, 08:13 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(VFaraon @  27.3.2007,  00:19 Найти цитируемый пост)
"достаточно сложны" - И об этом... 

Это автор делает вид, что он очень умный, а все остальные - ...

Одну причину Daevaorn назвал - некоторые члены можно проинициализировать только в списке инициализации (константы, ссылки), а также классы, не имеющие дефолт-конструктора.

Вторая - сложные члены данных (классы) сами инициализируются по умолчанию до входа в тело конструктора. Если добавить их инициализацию в список инициализации явно - будет вызван соответствующий конструктор, если нет - все равно будет вызван дефолт-конструктор. 
А потом ты присваиваешь им новое значение в теле конструктора и делаешь, таким образом, лишнюю работу. 

Не всегда это так уж страшно, а встроенные типы (int, double) вообще по умолчанию никак не инициализируются. 
Но для некоторых пользовательских типов это может означать выделение памяти под дефолт-значение, а затем удаление ее и выделение под новое значение. 

Так что инициализировать данные класса в списке инициализации - хорошая привычка.

Добавлено через 1 минуту и 33 секунды
Приведенный автором пример с count - абсолютно по барабану как писать...


--------------------
...
PM   Вверх
KelTron
Дата 27.3.2007, 11:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 745
Регистрация: 8.10.2006
Где: Красноярск

Репутация: нет
Всего: 38



Цитата
Списки инициализации членов
Чтобы избавиться от этой проблемы, в C++ находится очередное применение символу : — для
создания списков инициализации членов. Так называется список спецификаций конструкторов,
разделенных занятыми и расположенных между сигнатурой конструктора и его телом.
Код

class Foo {
public:
Foo(char*);
};
class Bar : public Foo {
public:
Bar(char*);
};
class BarBar {
private:
Foo f;
int x;
public:
BarBar();
};
Bar::Bar(char* s) : Foo(s) {...}
BarBar::BarBar : f(“Hello”), x(17) {...}

В конструкторе Bar список инициализации членов используется для инициализации базового класса
Foo. Компилятор выбирает используемый конструктор на основании сигнатуры, определяемой по
фактическим аргументам. При отсутствии списка инициализации членов сконструировать Bar было бы
невозможно, поскольку компилятор не мог бы определить, какое значение должно передаваться
конструктору базового класса Foo. В конструкторе BarBar список инициализации членов
использовался для инициализации (то есть вызова конструкторов) переменных f и х. В следующем
варианте конструктор работает не столь эффективно (если только компилятор не отличается
сверхъестественным интеллектом):
Код

BarBar::BarBar() : f(“Hello”)
{
x = 17;
}


Во втором варианте переменная х сначала инициализируется значением 0 (стандартное требование
C++) с использованием по умолчанию конструктора int без аргументов, а затем в теле конструктора
ей присваивается значение 17. В первом варианте имеется всего одна инициализация и потому
экономится один-два машинных такта. В данном примере это несущественно, поскольку переменная
х — целая, но если бы она относилась к более сложному классу с конструктором без аргументов и
перегруженным оператором присваивания, то разница была бы вполне ощутима.
Списки инициализации членов нужны там, где у базового класса или переменной нет конструктора без
аргументов (точнее, есть один и более конструктор с аргументами, но нет ни одного определенного
пользователем конструктора без аргументов). Списки инициализации членов не обязательны в тех
ситуациях, когда все базовые классы и переменные класса либо не имеют конструкторов, либо имеют
пользовательский конструктор без аргументов.

Когда ты пишешь, например, так:
Код

Counter() 
{
    count = 10;
}

Фактически происходит вот что:
Код

Counter() : count()
{
    count = 10;
}


Это сообщение отредактировал(а) KelTron - 2.4.2007, 08:26


--------------------
Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог.
Эвенгар Салладорский, основатель Школы Тьмы.
PM MAIL   Вверх
Fazil6
Дата 27.3.2007, 11:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(KelTron @  27.3.2007,  11:14 Найти цитируемый пост)
Фактически происходит вот что:

вообще-то не совсем , count не инициализируется нулем поумолчанию

PM MAIL   Вверх
Goryachev
Дата 27.3.2007, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 67
Регистрация: 23.2.2005
Где: Израиль

Репутация: нет
Всего: нет



Цитата(KelTron @  27.3.2007,  11:14 Найти цитируемый пост)
Когда ты пишешь, например, так:

Код

Counter() 
{
    count = 10;
}


Фактически происходит вот что:

Код

Counter() : count(0)
{
    count = 10;
}



Это не правильно.
Пример на gcc:
Код

#include <iostream>

class A
{
    int x;
public:
    int GetX() { return x; }
};

int main(int argc, char** argv)
{
    A a;
    std::cout<<a.GetX()<<std::endl;
    return 0;
}



Ресультат:
Код

4911516

То есть, мусор.
PM MAIL   Вверх
seacat79
Дата 27.3.2007, 11:55 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Новичок



Профиль
Группа: Участник
Сообщений: 46
Регистрация: 27.2.2007
Где: Украина, Одесса

Репутация: 1
Всего: 1



Цитата(Fazil6 @  27.3.2007,  11:40 Найти цитируемый пост)
вообще-то не совсем , count не инициализируется нулем поумолчанию


А если count это:  smile 
Код

class my_integer
{
    public:
         my_integer(int z=0);
}



Это сообщение отредактировал(а) seacat79 - 27.3.2007, 11:57
PM MAIL ICQ   Вверх
Goryachev
Дата 27.3.2007, 12:06 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 67
Регистрация: 23.2.2005
Где: Израиль

Репутация: нет
Всего: нет



Цитата(seacat79 @  27.3.2007,  11:55 Найти цитируемый пост)
А если count это:   

Код

class my_integer
{
    public:
         my_integer(int z=0);
}


Я думаю, что count подразумевался, как в оригинальном посте, т.е. int. ;)
PM MAIL   Вверх
KelTron
Дата 27.3.2007, 12:19 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 745
Регистрация: 8.10.2006
Где: Красноярск

Репутация: нет
Всего: 38



Исправлюсь, происходит вот что:
Код

Counter() : count()
{
    count = 10;
}



--------------------
Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог.
Эвенгар Салладорский, основатель Школы Тьмы.
PM MAIL   Вверх
vinter
Дата 27.3.2007, 12:52 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(Goryachev @  27.3.2007,  11:46 Найти цитируемый пост)
Это не правильно.

и где это не правильно?? это инициализация внутри тела конструктора!
Цитата(Goryachev @  27.3.2007,  11:46 Найти цитируемый пост)
Пример на gcc:

и что показывает твой пример? там не переопределен конструктор!
Цитата(KelTron @  27.3.2007,  12:19 Найти цитируемый пост)
Исправлюсь, происходит вот что:

вряд ли, скорее все соптимизировано в создание с инициализацией сразу, все таки встроенный тип.
Зачем ему сначала создаваться, а потом инициализироватьсяsmile



--------------------
Мой блог
PM MAIL WWW   Вверх
KelTron
Дата 27.3.2007, 13:00 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 745
Регистрация: 8.10.2006
Где: Красноярск

Репутация: нет
Всего: 38



Цитата(vinter @  27.3.2007,  12:52 Найти цитируемый пост)
вряд ли, скорее все соптимизировано в создание с инициализацией сразу, все таки встроенный тип.Зачем ему сначала создаваться, а потом инициализироваться

Ну не надо вдаваться в частные случаи, оно может и соптимизироваться, не в этом дело, в общем случае происходит именно то что я написал т.е. вызываются конструкторы по умолчанию для объектов, тип int здесь только потому, что он в первом посту. 


--------------------
Тысячами незримых нитей обвивает тебя Закон. Разрубишь одну - преступник. Десять - смертник. Все - Бог.
Эвенгар Салладорский, основатель Школы Тьмы.
PM MAIL   Вверх
Fazil6
Дата 27.3.2007, 13:04 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Завсегдатай
Сообщений: 1653
Регистрация: 3.5.2006
Где: Минск

Репутация: 35
Всего: 60



Цитата(vinter @  27.3.2007,  12:52 Найти цитируемый пост)
и что показывает твой пример? там не переопределен конструктор!

ты не понял. Речь о инициализации поумолчанию и Goryachev, в этом плане прав. 
Цитата(vinter @  27.3.2007,  12:52 Найти цитируемый пост)
вряд ли, скорее все соптимизировано в создание с инициализацией сразу, все таки встроенный тип.Зачем ему сначала создаваться, а потом инициализироваться

создается до вызова конструктора и если нет в списке инициализации, то значение не присваивается. Пока не произойдет присваивание внутри конструктора значение неопределено.

PM MAIL   Вверх
vinter
Дата 27.3.2007, 13:31 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Explorer
****


Профиль
Группа: Завсегдатай
Сообщений: 2735
Регистрация: 1.4.2006
Где: Н.Новгород

Репутация: 13
Всего: 56



Цитата(Fazil6 @  27.3.2007,  13:04 Найти цитируемый пост)
ты не понял. Речь о инициализации поумолчанию и Goryachev, в этом плане прав. 

теперь понял smile
Цитата(Fazil6 @  27.3.2007,  13:04 Найти цитируемый пост)
создается до вызова конструктора и если нет в списке инициализации, то значение не присваивается. Пока не произойдет присваивание внутри конструктора значение неопределено.

я про тожеsmile никакого дефолтного конструктора у встр. типов нет.
а вообще тут хватит постов Daevaorn и Earnest, а то развели тут smile 


--------------------
Мой блог
PM MAIL WWW   Вверх
JackYF
Дата 27.3.2007, 15:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


полуавантюрист
****


Профиль
Группа: Участник
Сообщений: 5814
Регистрация: 28.8.2004
Где: страна тысячи озё р

Репутация: 18
Всего: 162



Цитата(vinter @  27.3.2007,  13:31 Найти цитируемый пост)
Earnest, а то развели тут smile  


оффтоп: гы, у Earnest один пост, у KelTronа  3. Странный у тебя счетчик. Видать, был мусором проинициализирован  smile (это применительно к обсуждаемой теме smile

Без обид smile




--------------------
Пожаловаться на меня как модератора можно здесь.
PM MAIL Jabber   Вверх
Earnest
Дата 27.3.2007, 15:10 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Экс. модератор
Сообщений: 5962
Регистрация: 17.6.2005
Где: Рязань

Репутация: 53
Всего: 183



Цитата(vinter @  27.3.2007,  14:31 Найти цитируемый пост)
я про тоже никакого дефолтного конструктора у встр. типов нет.

Тоже не совсем правильно. Если написать int a=int(); то получим 0. Правда так в нормальном коде не пишут? но зато это часто встречается в шаблонах. Например, объявляем стандартный вектор интов заданной длины:
Код

   std::vector<int> A(10);

   // это эквивалентно следующей строке
   std::vector<int> A(10, int());    // там аргумент по умолчанию _Tp val = _Tp()
   // так что получим массив, инициализированный нулями.

Это, кстати, очень удобно. Скажем, есть отображение std::map<CString, int> - допустим, мы хотим подсчитать, сколько раз каждая строка встречается в каком-то тексте.
Пишем:
Код

   std::map<CString, int> counts;   
   ...
   CString str = ReadNextString();
   counts[str]++;    .. если такого элемента еще нет, он создастся и инициализируется нулем!

Если бы не было дефолт-конструктора, пришлось бы либо городить спец.класс counter с инициализацией, либо проверять, что строки еще нет и инициализировать счетчик нулем.


--------------------
...
PM   Вверх
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
1 Пользователей читают эту тему (1 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.1083 ]   [ Использовано запросов: 21 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.