2014 dxdy logo

Научный форум dxdy

Математика, Физика, Computer Science, Machine Learning, LaTeX, Механика и Техника, Химия,
Биология и Медицина, Экономика и Финансовая Математика, Гуманитарные науки




Начать новую тему Ответить на тему На страницу Пред.  1, 2, 3  След.
 
 Re: C++ наследование
Сообщение29.02.2016, 19:54 
Заслуженный участник
Аватара пользователя


30/01/06
72407
Это всё косметические правки. Для начала надо объяснить, что:
- Реализация класса должна быть надёжной. Конструктор, не проверяющий входные данные, карается смертной казнью.
- По возможности - максимально последовательной. Незачем изобретать два разных способа хранения данных ради экономии одного байта.
- protected существует, не чтобы открывать реализацию, а чтобы предоставить дополнительный интерфейс потомкам.
- Любая передача доступа к внутренним деталям реализации наружу идёт через const.
Ну и тому подобные принципы и заповеди. Например, нельзя делать сначала плохой код, оставлять его в программе, и внешними прибамбасами пытаться сделать из него хороший. Если хочется разделить реализацию на быстрое ядро и fool-proof добавку, добавка должна быть обёртывающим слоем, не дающим прямого доступа к ядру: например, включение, или private наследование (которое новичкам не рекомендуется). Мелочи типа того, что не стоит придумывать объект большого размера, данные которого хранятся в самом объекте, а не в динамически выделяемой памяти.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 00:00 
Аватара пользователя


07/02/12
1403
Питер
Munin в сообщении #1103217 писал(а):
Любая передача доступа к внутренним деталям реализации наружу идёт через const

Не очень понял, что Вы имеете в виду. Можно по-подробнее?

Munin в сообщении #1103217 писал(а):
Мелочи типа того, что не стоит придумывать объект большого размера, данные которого хранятся в самом объекте, а не в динамически выделяемой памяти

Почему Вы так считаете?

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 00:40 
Заслуженный участник
Аватара пользователя


30/01/06
72407
bondkim137 в сообщении #1103266 писал(а):
Почему Вы так считаете?

Потому что стек куда более исчерпаем, чем heap. По крайней мере, ну лет 10 назад - точно был. Не знаю, что там с x64, может, это правило и устарело...

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 00:47 
Заслуженный участник


04/05/09
4582
Munin в сообщении #1103275 писал(а):
bondkim137 в сообщении #1103266 писал(а):
Почему Вы так считаете?

Потому что стек куда более исчерпаем, чем heap. По крайней мере, ну лет 10 назад - точно был. Не знаю, что там с x64, может, это правило и устарело...
И сейчас так же, хотя лимиты увеличились.
Разница в том, что стек должен быть непрерывным, т.е. под него память надо выделить заранее, а в куче только каждый объект/массив должен быть непрерывным. В принципе, можно и стек сделать расширяемым, но это приведёт к усложнению и замедлению кода вызовов функций, что противоречит идеологии C/C++.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 00:51 
Аватара пользователя


07/02/12
1403
Питер
Munin в сообщении #1103275 писал(а):
Потому что стек куда более исчерпаем, чем heap

Понял, Вы рассматриваете случай со статическим размещением объекта в локальных переменных.
Большие объекты и сейчас не принято размещать непосредственно на стеке (в локальных переменных).
Стек до сих пор стараются не перегружать - проблемы с адресным пр-вом нет, но он до сих пор не умеет выгружаться (разве что в swap).
Но сам объект делать большим впринципе ничего плохого нет - он создается в динамической памяти, а на стеке хранится ссылка (все чаще смарт-ссылка на него).

-- 01.03.2016, 00:54 --

venco в сообщении #1103276 писал(а):
Разница в том, что стек должен быть непрерывным, т.е. под него память надо выделить заранее, а в куче только каждый объект/массив должен быть непрерывным. В принципе, можно и стек сделать расширяемым, но это приведёт к усложнению и замедлению кода вызовов функций, что противоречит идеологии C/C++

Уточните пожалуйста, если не сложно. Боюсь, я неоднозначно могу понять ваше утверждение.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 01:16 
Заслуженный участник


04/05/09
4582
bondkim137 в сообщении #1103278 писал(а):
venco в сообщении #1103276 писал(а):
Разница в том, что стек должен быть непрерывным, т.е. под него память надо выделить заранее, а в куче только каждый объект/массив должен быть непрерывным. В принципе, можно и стек сделать расширяемым, но это приведёт к усложнению и замедлению кода вызовов функций, что противоречит идеологии C/C++

Уточните пожалуйста, если не сложно. Боюсь, я неоднозначно могу понять ваше утверждение.
Эффективная, с поддержкой в системе команд процессора, реализация вызова функции требует, чтобы стек был непрерывным в памяти (и ещё рос вниз, но это несущественные детали). Т.е. в адресном пространстве процесса весь диапазон адресов стека должен быть зарезервирован под стек, и ничего больше. Этот диапазон адресов надо выделить заранее, и ни для чего другого (куча, отображение файлов, и т.п.) его использовать нельзя. Причём это делает компилятор, не очень то и зная, что за программа, и сколько стека ей надо. И если выделенное под стек адресное пространство не используется, то это просто потерянная память. Поэтому стараются по умолчанию выделить некоторое компромиссное количество стека. Эту величину обычно можно поменять специальными командами компилятору или компоновщику (линкеру), но про эти команды мало кто знает или вспоминает.
В теории, можно попробовать использовать всё адресное пространство процесса динамически для кучи и стека - куча растёт снизу вверх, стек сверху вниз, до какой получится точки встречи, но в популярном ныне много-поточном программировании это не работает совсем, т.к. у каждого потока свой стек. Обычно стек запускаемого потока выделяется также в куче, какого-либо фиксированного размера (см. параметры функции запуска потока), и опять-таки, потом при необходимости увеличить этот размер нельзя, как, собственно, нельзя и увеличить размер области памяти, выделенной в куче, особенно если увеличивать надо вниз.
Учитывая всё это, принято не выделять больших массивов/объектов в стеке, а пользоваться для этого кучей, чтобы не вызвать переполнение стека. Кстати, переполнение стека может очень плохо диагностироваться, прямая проверка в начале каждой функции слишком дорого стоит, чтобы это делать по умолчанию.
Всё вышесказанное относится к C/C++ (и некоторым другим высоко-производительным языкам), и не относится, например, к Java. Насколько я помню, там стек фрейм при вызове функции тоже выделяется в куче. Хоть это и медленнее, но система безопасности Java обязывает.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 01:33 
Заслуженный участник
Аватара пользователя


30/01/06
72407
bondkim137 в сообщении #1103278 писал(а):
Но сам объект делать большим впринципе ничего плохого нет - он создается в динамической памяти, а на стеке хранится ссылка (все чаще смарт-ссылка на него).

Это вы с Java или C# путаете.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 01:39 


05/09/12
2587
Однако, это не мешает Java иметь ограниченный размер стека потока (который можно задать, но по умолчанию он весьма мал), и вызывать регулярное стековерфлоу у любителей рекурсивных функций (в сочетании с отсутствием в языке ТСО это случается почти всегда). Мне пришлось реализовывать собственное ТСО в своем Lisp-интерпретаторе на Java, но все равно это не решает всей проблемы, и приходится нарезать стек побольше при запуске.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 02:24 
Аватара пользователя


07/02/12
1403
Питер
Munin в сообщении #1103287 писал(а):
Это вы с Java или C# путаете

Я их не знаю (по крайней мере на том уровне, что б делать подобные заявления).
А за С++ готов побиться. На С++ сейчас во всех достаточно больших не трешовых проектах на архитектурном уровне (везде, где использование низкого уровня неоправданно), используют смарт-ссылки. Это статистически более выгодно, чем ловить баги, вызванные неоднозначностью в создании/удалении объектов - хоть в куче, хоть на стеке.
Хотя прибедняюсь конечно, за C# и Java тоже могу в этом контексте постоять. У них, к слову, ссылки обычные, быстрые. Но прилагающийся объем проблем при переходе от смарт-ссылок к обычным, но с Garbage-Collector-ом, особенно в контексте мультизадачных приложений, из моего опыта ни к чему хорошему не приводит. Т.е. задача освобождения памяти в больших мультизадачных приложениях и сервисах - это минимальная из проблем.

-- 01.03.2016, 02:45 --

venco в сообщении #1103284 писал(а):
Причём это делает компилятор

Это делает ОС. Она использует данные, которые зашиваются в исполняемый файл, как хинты.
venco в сообщении #1103284 писал(а):
если выделенное под стек адресное пространство не используется, то это просто потерянная память

Нет, это всего лишь потерянное адресное пр-во. Память выделяется по мере его использования. По-странично. Обращение к ранее неиспользованной странице вызывает исключение, ОС выделяет реальную память под это дело и т.д.
venco в сообщении #1103284 писал(а):
Поэтому стараются по умолчанию выделить некоторое компромиссное количество стека

В обычных клиентских 64-х разрядных приложениях под стек можно выделять столько пр-ва, сколько не жалко. К реальной памяти это отношения не имеет. В серверных приложениях даже в 64-х битах стоит осозновать рамки приличия, тем более что сейчас есть сервисы с десятками (сотней) тысяч потоков (соответсвенно стеков).
venco в сообщении #1103284 писал(а):
В теории, можно попробовать использовать всё адресное пространство процесса динамически для кучи и стека - куча растёт снизу вверх, стек сверху вниз

Куча растет как и куда попало, стек растет сверху вниз только для каждого отдельного потока. Для мультизадачных приложений он растет как расческа с разными зубьями.
venco в сообщении #1103284 писал(а):
Учитывая всё это, принято не выделять больших массивов/объектов в стеке, а пользоваться для этого кучей, чтобы не вызвать переполнение стека. Кстати, переполнение стека может очень плохо диагностироваться, прямая проверка в начале каждой функции слишком дорого стоит, чтобы это делать по умолчанию

Это так. Хотя на практике выделение объекта в куче чаще вызвано необходимостью его где-нить запомнить (удержать) за пределами видимости текущих локальных переменных, чем ограниченностью стека.
venco в сообщении #1103284 писал(а):
и не относится, например, к Java

Это зависит от реализации. Java-условно говоря, интерпретируемая среда с хитростями. Можно переносить и уплотнять память (да и стек) во время работы. Далеко не всегда правда это работает эффективно.

-- 01.03.2016, 02:51 --

_Ivana, если вы осознанно активно эксплуатируете стек, то нужно либо однозначно понимать, что конкретная реализация вам это позволяет делать, либо сделать свою через кучу. Второй вариант, как правило, не сильно сложнее, но более устойчив.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 02:54 
Заслуженный участник


04/05/09
4582
Честно говоря, bondkim137, я не очень понял, зачем вы попросили подробностей. Вы, похоже, и сами знаете все детали, и должны понимать, что просто и однозначно тут не ответить. Но новичку, а именно новичок является автором темы, лучше дать более-менее универсальную рекомендацию - стараться выделять большие массивы и объекты в куче.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 03:25 


05/09/12
2587
bondkim137 в сообщении #1103298 писал(а):
либо сделать свою через кучу. Второй вариант, как правило, не сильно сложнее
Насколько я понимаю, возможно решить вопрос 3 путями:
1) увеличением размера стека потока
2) созданием новых потоков для продолжения вычислений, когда стек текущего заполнен
3) полной переработкой алгоритма из рекурсивного в итеративный (т.к. рекурсивные вызовы даже без параметров забивают стек адресами возврата)
Я остался на варианте 1), потому что вариант 2) меня не устроил, а вариант 3) - реализовав половину (неэффективно), уже получил непозволительное замедление, а на эффективную реализацию не хватило ума и терпения, на фоне такого соблазнительного первого варианта.

ЗЫ я создавал тему на этом форуме - не нашлось желающих прокомментировать.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 03:26 
Аватара пользователя


07/02/12
1403
Питер
venco, да, простите. Я немного потерялся - невежливо к Вам и ТС получилось.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 03:32 
Заслуженный участник
Аватара пользователя


30/01/06
72407
bondkim137 в сообщении #1103298 писал(а):
Я их не знаю (по крайней мере на том уровне, что б делать подобные заявления).
А за С++ готов побиться. На С++ сейчас во всех достаточно больших не трешовых проектах на архитектурном уровне (везде, где использование низкого уровня неоправданно), используют смарт-ссылки.

Заметьте, "на архитектурном уровне". То есть, это разработчик класса делает сам руками. С этим я не спорю. Но автор (ТС) именно так именно не сделал, на что я и намекнул.

Теперь прояснилось, о чём речь? Больше нет охоты "побиться"?

-- 01.03.2016 03:33:35 --

bondkim137 в сообщении #1103307 писал(а):
venco, да, простите. Я немного потерялся - невежливо к Вам и ТС получилось.

Жду и свою долю.

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 03:41 
Аватара пользователя


07/02/12
1403
Питер
_Ivana
Вариант 1 эффективен в качестве ad-hoc, если адресное пр-во позволяет (если 64-бита грубо говоря).
При этом, он менее эффективен, чем куча, если у вас огромное кол-во потоков в процессе и есть возможность переиспользовать объекты между потоками. В случае со статическим размещением на стеке такой возможности не будет.

Вариант 2 мне он кажется довольно неэффективной экзотикой. Возникнет масса проблем - начиная с отслеживанием состояния переполенности стека, заканчивая организации такого сегментированного стека. Хотя в узких случаях и он может применяться. При ооочень глубоких обходах в глубину например. Хотя тут ему лучше модернизироваться в Вариант 3.

Вариант 3 наверное слишком кардинальный. Но вот Вариант 4, как гибрид между 3 и 1 в рамках конкретной задачи имеет право на существование. Но если даже 1 решило все проблемы, то, как самый простой и негрязный способ, это правильный способ.

-- 01.03.2016, 03:43 --

Munin в сообщении #1103309 писал(а):
Теперь прояснилось, о чём речь? Больше нет охоты "побиться"?

Да я вроде на самом деле и не пытаюсь биться. Поговорить хотелось с пользой для кого-то

Munin в сообщении #1103309 писал(а):
Жду и свою долю.

Вы это про соседнюю тему или про эту?

 Профиль  
                  
 
 Re: C++ наследование
Сообщение01.03.2016, 17:16 
Заслуженный участник
Аватара пользователя


30/01/06
72407
bondkim137 в сообщении #1103310 писал(а):
Вы это про соседнюю тему или про эту?

Я про извинения.

 Профиль  
                  
Показать сообщения за:  Поле сортировки  
Начать новую тему Ответить на тему  [ Сообщений: 39 ]  На страницу Пред.  1, 2, 3  След.

Модераторы: Karan, Toucan, PAV, maxal, Супермодераторы



Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей


Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Найти:
Powered by phpBB © 2000, 2002, 2005, 2007 phpBB Group