![]() |
|
Модераторы: bsa |
![]()
|
|
| wowka19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 285 Регистрация: 30.11.2011 Репутация: нет Всего: нет |
Объясните пожалуйста разницу между приведенными ниже конструкторами.
Я понимаю, что объект в итоге проинициализируется одинаково, и что первый пример единственный если m_data - const. И еще часто встречаю рекомендации использовать первый пример. Но почему? Меня интересуют не только эстетические моменты и случай с const, но и внутреннюю интерпретацию этого кода (то есть что скрывается под капотом)
|
|||
|
||||
| bsa |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Модератор Сообщений: 9185 Регистрация: 6.4.2006 Где: Москва, Россия Репутация: 85 Всего: 196 |
представь, что у тебя m_data имеет сложный тип (выделяет память в конструкторе и освобождает в деструкторе). Если ты поставишь во все методы класса Data логирование, то увидишь:
1.
2.
Кстати, если у класса Data нет конструктора по умолчанию, то второй варианты у тебя не скомпилируется. Чисто теоретически, можно предположить, что в для простых типов компилятору в первом случае будет легче оптимизировать инициализацию. |
||||
|
|||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
под капотом суть одно и то же, а разница, она же ошибка - тут
дело в том, что m_data = 0; это присваивание, а не инициализация. инициализация произошла раньше (мусором). а перед { это как раз инициализация. разница конечно тонкая, но это, например, единственный способ инициализировать ссылки, а так же члены, которым нельзя присваивать - упомянутые вами константы и объекты с закрытым оператором присваивания. кроме того, считается, что инициализируя явно, меньше вероятность забыть про вновь добавленный член. Добавлено @ 22:42 bsa все подробно расписал))) а компилятор все это соптимизирует в nop. Это сообщение отредактировал(а) baldina - 6.11.2012, 22:43 |
|||
|
||||
| wowka19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 285 Регистрация: 30.11.2011 Репутация: нет Всего: нет |
я имел ввиду, что после отработки конструктора в обоих случаях мы получим идентичные объекты. bsa, не совсем понял. что это значит? Это сообщение отредактировал(а) wowka19 - 7.11.2012, 12:29 |
|||
|
||||
| Dem_max |
|
|||
![]() Эксперт ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 1780 Регистрация: 12.4.2007 Репутация: 4 Всего: 39 |
Не идентичные объекты, а значения, но это для простых объектов у которых используется оператор присваивания (тут нет никакой разницы как ты сделаешь). Для сложных объектов инициализация только так MyClass::MyClass() : m_data(0) {} Это сообщение отредактировал(а) Dem_max - 7.11.2012, 12:33 -------------------- Американские программисты долго не могли понять, почему русские при зависании Windоws всё время повторяют "Твой зайка написал" ("Yоur bunnу wrоte") |
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
nop - "нет операции", пусто bsa расписал логику работы конструктора, в режиме отладки так и будет, но поскольку функции пустые, компилятор преобразует это в "ничто", не будет вызова пустых функций. даже копирования временных объектов скорее всего не будет. |
|||
|
||||
| wowka19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 285 Регистрация: 30.11.2011 Репутация: нет Всего: нет |
ладно... похоже без спец. литературы не обойтись. Посоветуйте пожалуйста книжку, ясно и подробно объясняющую моменты подобные в этой теме. то есть не какой нибудь "C++ за 21 день/24 часа", а что-то фундаментальное.
|
|||
|
||||
| baldina |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
любою толстую возьми с нерусской фамилией автора
Страуструп, Прата, Лафоре - у каждого из них есть толстые книжки типа "язык программирования С++" Добавлено через 2 минуты и 43 секунды если мои слова про оптимизацию компилятором сбивают с толку, просто игнорируйте их. это не так важно для понимания. важнее семантика языка (т.е. то что bsa написал) и правила (относительно инициализации констант, ссылок, прочих типов без доступного оператора присваивания) |
|||
|
||||
| wowka19 |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 285 Регистрация: 30.11.2011 Репутация: нет Всего: нет |
ну хотелось бы поконкретнее, исходя из собственного опыта, а не просто "толстые книжки". у того же страуструпа этих толстых книжек не одна.
на счет оптимизации я как раз понимаю - тут чисто здравая логика помогает. |
|||
|
||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Вопрос, кстати хороший. Действительно, возникает большая путаница в этом вопросе.
Чем кардинально отличается инициализация от присваивания. Присваивание должно осуществляется на уже инициализированной памяти, а инициализация происходит на памяти, содержимое которой заранее не известно (мусор), да и неважно. Для встроенных типов (int,char * etc) большой разницы нет, поскольку что в случае инициализации, что в случае присваивания, новое значение переменной затрёт старое, и всё. Для сложных типов всё сложно))) Инициализация просто определит (ту мусорную) память, отведённую под переменную этого типа, значащими величинами (в том числе будет проинициализирована таблица виртуальных вызовов). Присваивание переопределит память (которая считается уже проинициализированной адекватными значениями), отведённую под переменную этого типа. И вот здесь как раз таятся подводные камни. Рассмотрим довольно часто встречающийся пример:
Вот несмотря на то, что программист написал про "инициализацию", на самом деле происходит присваивание. И что получается в итоге? Чтобы присвоить новое значение строке myData.string нужно избавиться от старого (иначе - утечка памяти). Но проблема в том, что старого значения не существует (оно мусорное, непроинициализированное никак). Что делать? Как раз нужно предварительно проинициализировать переменную myData (в этом случае содержимое памяти, отведённое под саму переменную в начале выполнения программы неважно, оно будет заполнено корректными значениями), а не пытаться ей присвоить какое-то значение (в этом случае содержимое памяти, отведённой под myData, уже играет роль). Итог: нужно писать конструктор структуры my_data (и деструктор тоже). В реальности всё ещё сложнее. "Операция присваивания" приобретает статус "оператора присваивания" (то есть по специальным правилам вызывается заранее определённая функция под названием operator=), вызываются нужные конструкторы и деструкторы, bsa всё здорово описал. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
подумалось, удобно объяснять на шаблонном классе
когда компилятор не сможет инстанциировать этот шаблон (т.е. создать конкретный класс для конкретного типа T)? иными словами, какие условия накладываются на тип T? Это вытекает из последовательности вызовов, описанных bsa 1. Наличие public конструктора по-умолчанию вида T() (возможно, сгенерированного компилятором по умолчанию) 2. Наличие преобразования из U в T, например конструктора T(U), если U и T различны 3. Наличие public T& operator=(const T&); (возможно, сгенерированного компилятором по умолчанию) 4. Наличие public конструктора копирования T(const T&); для копирования временного объекта, если U и T разные типы, либо для копирования аргумента, если U и T один тип под эти условия подходят все встроенные типы, именно поэтому например для int создается ощущение, что разницы нет. В случае кода
требование лишь одно, наличие соответствующего public конструктора T(const U&); (в случае, если Т и U один тип, это будет конструктор копирования T(const T&);) Так что последний способ короче, более общий (работает в большем числе случаев, в т.ч. для констант и ссылок), и вдобавок производительней, т.к. операций в общем случае производится меньше. Последнее имеет значение, если такие объекты создаются довольно интенсивно, а T имеет не простые конструктор и деструктор. |
||||
|
|||||
| wowka19 |
|
||||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 285 Регистрация: 30.11.2011 Репутация: нет Всего: нет |
голова распухла - шапка не налазит)
кажись моя проблема в этом:
Я думал, что любой мусор будет являться значащей(адекватной) величиной любого типа. На примере short - диапазон этого типа 65536 значений, что является максимальным количеством состояний памяти размером 16 бит, отведенных под этот тип. Другими словами любой мусор в любом 16-битном участке памяти является корректным short. Или я не прав? отсюда и мнение, что конструкторы (ниже) дадут идентичный бинарный выхлоп (то есть будут являться одним и тем же набором команд/инструкций):
Это сообщение отредактировал(а) wowka19 - 7.11.2012, 21:00 |
||||
|
|||||
| feodorv |
|
|||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Комодератор Сообщений: 2214 Регистрация: 30.7.2011 Репутация: 12 Всего: 45 |
Вопрос, что считать "корректным". На мой взгляд, мусор считаться корректным не может. Но в приведённом Вами коде с Class2 изначально мусорное значение поля m_data роли не играет. И именно потому, что тип m_data является простым встроенным типом, для которого что инициализация, что присвоение - всё едино. Но как только мы начинаем иметь дело со сложными типами, инициализация начинает резко отличаться от присвоения.
Результат они должны дать одинаковый, но вот чтобы прямо-таки одинаковый бинарный код - не уверен. -------------------- Напильник, велосипед, грабли и костыли - основные инструменты программиста... |
|||
|
||||
| baldina |
|
||||
![]() Эксперт ![]() ![]() ![]() ![]() Профиль Группа: Завсегдатай Сообщений: 3433 Регистрация: 5.12.2007 Где: Москва Репутация: 15 Всего: 101 |
тем не менее значение будет вполне корректным, хотя и неизестным, случайным. его случайность определяет его бесполезность. так что, wowka19, от его корректности толку мало Добавлено через 3 минуты и 21 секунду
для простых типов да. но не для всех. т.к. мы говорим об ООП, под объектом может быть нечто далекое от тривиальных встроенных типов. это элемент культуры: если будешь всегда инициализировать до тела конструктора, в менее очевидных случаях вероятность ошибки меньше. |
||||
|
|||||
| NoviceF |
|
|||
|
Опытный ![]() ![]() Профиль Группа: Участник Сообщений: 313 Регистрация: 13.3.2012 Где: Ростов-на-Дону Репутация: 2 Всего: 2 |
Рекомендую - Скотт Мэйерс "Эффективное использование C++" Третье издание (2006 год), "правило 4: Прежде чем использовать объекты, убедитесь, что они инициализированы". |
|||
|
||||
![]()
|
| Правила форума "C/C++: Для новичков" | |
|
|
Запрещается! 1. Публиковать ссылки на вскрытые компоненты 2. Обсуждать взлом компонентов и делиться вскрытыми компонентами
Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, JackYF, bsa. |
| 0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей) | |
| 0 Пользователей: | |
| « Предыдущая тема | C/C++: Для новичков | Следующая тема » |
|
|
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности Powered by Invision Power Board(R) 1.3 © 2003 IPS, Inc. |