Повторю вопрос специально для вас: "какие накладные расходы на ООП есть, например, у std::vector, у которого нет виртуальных методов, но есть инкапсуляция".
Вы бы еще за демонстрациями на говнокод.ру сходили бы. Единственный из показанных вами репозиториев, который имеет хотя бы нормальное количество звезд -- 99 на данный момент -- содержит просто лабы по программированию: "A simple mathematical matrix class written in C++ to be reused for future assignments in my Computational Linear Algebra class."
Да еще и с откровенной припиской: "The code almost definitely constains significant bugs and solves numerous problems in a naive, inefficient, and incomplete manner."
Именно потому, что в Си ООП нет, то накладные расходы на ООП в Си равны нулю.
Да, да, да. Поэтому когда в каком-нибудь Си-шном проекте, типа OpenSSL, потребуются аналоги виртуальных функций, которые колхозятся на структурах с указателями на функции, то это все абсолютно бесплатно. Ага.
Теперь же, когда выяснили, вы приведете какие-то цифры, подтверждающие ваше утверждение? Или после общих слов о том, что все тормозят одинаково в процентном отношении относительно всего остального (или что вы там имели в виду) никаких количественных оценок уже не предполагается?
А имел в виду, что, программируя на С++, мы будем вынуждены, в отличие от Си, использовать реализацию ООП, так как на ООП построены библиотеки С++ и практика программирования на С++.
Тут бы очень хотелось выяснить кто такие "мы".
А практика программирования на C++ уже давным-давно (лет 25 минимум, а то и все 30) держится на мультипарадигменности, где ООП соседствует как с обычным процедурным подходом, так и с обобщенным программированием.
Я писал, что накладные расходы C++ возникают именно из-за поддержки ООП
Уже несколько раз цитировал что именно вы написали, повторяться не буду. Просто еще раз напомню, что рассуждать о накладных расходах на что-то по сравнению с чем-то можно только в случае, если это "что-то" есть в том самом "чем-то". В Си ООП нет, поэтому оценивать накладные расходы C++ на ООП в сравнении с Си бессмысленно. Не удивительно, что фактически подтвердить свои утверждения вы не можете.
Вы так уверены, что вам всегда будут одновременно нужны для обработки все поля агрегирующего объекта, в том числе и агрегируемый? Может, наоборот, вы забьёте кеш лишними данными?
Если не нужны, то я могу разнести A и B. Или могу переместить A внутри B.
Нет, что вы, так рассуждаю.
Оно и заметно.
Даже если предположить
Может хватит ваших предположений? Давайте с фактами, а то у вас с этим как-то туго пока. Слов много, фактов нет.
что ниоткуда само по себе не следует
Еще как следует, когда у нас один объект внутри другого, а не два в разных местах.
то никто не мешает компилятору разместить в памяти вынесенный агрегированный объект сразу до или после агрегирующего
Можно ли увидеть примеры сего чуда? Это во-первых. Во-вторых, вот у вас будет нечто вида:
class B {
private C c = new C();
private D d = new D();
private A a = new A();
...
}
Где конструкторы C и D генерят тучу собственных мелких (или не очень) объектов. Как компилятор поймет, что рядом с B нужно размещать именно A?
Разница будет в один указатель.
Разница в один указатель -- это в два раза больше, чем те четыре, которые я привел в качестве примера.
На накладные расходы, связанные с хранением самого A, вы в любом случае не можете повлиять, агрегируя A в другой класс.
Правда? А если смогу?
А где у вас хранится в памяти тело агрегированного объекта относительно тела агрегирующего - это просто деталь реализации.
Ну да, ну да. Абсолютно несущественная, особенно если брать в расчет cache locality.
В C++ всё равно так и так любой объект должен иметь возможность представляться ссылкой, так что сложно представить, как это различие можно практически эксплуатировать без ub.
Простите не распарсил.
А можно встречный вопрос: вы вообще на C++ программировали?
Я не говорил о том, чтобы писать на C++ в стиле Си. Читайте внимательнее, пожалуйста.
Речь шла о том, что в C++ вы запросто можете программировать в процедурном стиле, как и на Си. Только делать это будет удобнее и надежнее. За счет, например, наличия ad-hoc полиморфизма, ссылок и отсутствия неявных преобразований из void*.
А вы понимаете разницу между ссылочными типами (reference types) и типами-значениями (value types) в языках с GC?
Если у вас в Java тип A -- это reference type, т.е.:
public class A {...}
то когда вы делаете член типа A в классе B (который так же reference type):
public class B {
private A a;
...
}
то в B у вас хранится только ссылка на экземпляр A. И вы не можете повлиять на накладные расходы, связанные с хранением самого A и представлением ссылки на A внутри B.
"Это по сути вообще ни о чём, на реализацию ООП в C++ уходит гораздо больше оверхеда (по сравнению с С)."
Это сложно воспринять как-то иначе как накладные расходы на ООП в C++. А так как в чистом Си ООП нет, то когда в Си нам придется использовать ООП, то мы будет делать это вручную и обойдется нам это дешевле, чем в C++.
Я имею в виду чисто процедурный стиль.
Тогда при чем здесь ООП в C++? На C++ вы точно так же (даже надежнее и безопаснее) сможете использовать процедурный стиль, как и в Си.
Или вы в C++ видите какие-то дополнительные издержки даже на процедурный стиль в сравнении с Си?
Вы в моих словах нашли пафос? Перечитайте, пожалуйста.
Я б ещё, может, и мог с огромным усилием поверить, что в ваших программах негде сэкономить 4 байта, кроме как на счётчике ссылок, и вот именно он разрушил бы всё оптимальное размещение в памяти.
С чего вы взяли, что речь идет о счетчиках ссылок?
Ручное управление памятью (по крайней мере в моем мире) -- это не только ручной вызов new/delete (или malloc/calloc/free), и даже не деление на стек/хип. Это еще и использование union-ов, пулы/арены памяти и placement new. А так же агрегирование данных, когда вы объект класса A можете сделать полем класса B и память для A будет частью памяти для B (тогда как в языках с GC если у вас A -- это ссылочный тип, то частью другого ссылочного типа B вы его не сделаете).
Но уж никак не в объектно-ориентированном языке C++ с повсеместными таблицами виртуальных методов, длинами векторов и прочей шнягой поддержки выполнения.
Зная как вы не можете в обоснование собственных утвержений я даже и не стал заострять внимание вот на этом: "на реализацию ООП в C++ уходит гораздо больше оверхеда (по сравнению с С)". Но раз вы сами завели эту шарманку, то может поделитесь цифрами о том, насколько рукопашная реализация ООП на чистом Си выгоднее, чем поддерживаемая компилятором и рантаймом в С++?
И вот в такой задаче автоматическая сборка мусора заняла всего 50% времени выполнения. Это по сути вообще ни о чём
Наверное, я чего-то не понимаю в программировании, но когда половина времени уходит не на полезную работу, а на менеджмент памяти, то в этом нет ничего хорошего. А когда это еще и характеризуют как "по сути ни о чём", то такое ощущение, что не понимаю я вообще ничего.
это либо очень узкая область низкоуровневых задач (но даже там лучше память выделять вообще в статические массивы), либо лютый бабушкин анахронизм.
Либо работа с большими объемами данных, где экономия 4-х байт на каждый объект приводит к снижению потребления памяти на сотни мегабайт. А с учетом того, что быстрые кэши маленькие, а загрузка в них данных из ОП медленная, то экономия на потребляемых объемах как-то сама собой трансформируется в выигрыш по скорости.
Вы так говорите, как будто компилятору позволено так поступать с корректной программой. А для того, чтобы написать корректную программу вовсе не обязательно упарываться изучением ассемблерного выхлопа. Скорее даже наоборот.
Повторю вопрос специально для вас: "какие накладные расходы на ООП есть, например, у std::vector, у которого нет виртуальных методов, но есть инкапсуляция".
Ну расскажите, пожалуйста, какие накладные расходы на ООП есть, например, у std::vector, у которого нет виртуальных методов, но есть инкапсуляция.
Вы бы еще за демонстрациями на говнокод.ру сходили бы. Единственный из показанных вами репозиториев, который имеет хотя бы нормальное количество звезд -- 99 на данный момент -- содержит просто лабы по программированию: "A simple mathematical matrix class written in C++ to be reused for future assignments in my Computational Linear Algebra class."
Да еще и с откровенной припиской: "The code almost definitely constains significant bugs and solves numerous problems in a naive, inefficient, and incomplete manner."
Отучаемся говорить за всех (c)
И даже не в минутах.
Да, да, да. Поэтому когда в каком-нибудь Си-шном проекте, типа OpenSSL, потребуются аналоги виртуальных функций, которые колхозятся на структурах с указателями на функции, то это все абсолютно бесплатно. Ага.
Вот и приходится выяснять что же вы имели в виду.
Теперь же, когда выяснили, вы приведете какие-то цифры, подтверждающие ваше утверждение? Или после общих слов о том, что все тормозят одинаково в процентном отношении относительно всего остального (или что вы там имели в виду) никаких количественных оценок уже не предполагается?
Тут бы очень хотелось выяснить кто такие "мы".
А практика программирования на C++ уже давным-давно (лет 25 минимум, а то и все 30) держится на мультипарадигменности, где ООП соседствует как с обычным процедурным подходом, так и с обобщенным программированием.
Уже несколько раз цитировал что именно вы написали, повторяться не буду. Просто еще раз напомню, что рассуждать о накладных расходах на что-то по сравнению с чем-то можно только в случае, если это "что-то" есть в том самом "чем-то". В Си ООП нет, поэтому оценивать накладные расходы C++ на ООП в сравнении с Си бессмысленно. Не удивительно, что фактически подтвердить свои утверждения вы не можете.
Прекрасно, начиналось все с
а закончилось общими фразами
Да вы просто мастер аргументировать вами же высказанные утверждения.
Только вот тормозят C++ программы несколько не так, чем программы на Ruby, например.
А я и не аргументировал в пользу C++, я просил вас привести подтверждения того, что у C++ больше накладных расходов на поддержку ООП, чем в Си.
Вы, ожидаемо, в подтверждение собственных слов не смогли.
Если не нужны, то я могу разнести A и B. Или могу переместить A внутри B.
Оно и заметно.
Может хватит ваших предположений? Давайте с фактами, а то у вас с этим как-то туго пока. Слов много, фактов нет.
Еще как следует, когда у нас один объект внутри другого, а не два в разных местах.
Можно ли увидеть примеры сего чуда? Это во-первых.
Во-вторых, вот у вас будет нечто вида:
Где конструкторы C и D генерят тучу собственных мелких (или не очень) объектов. Как компилятор поймет, что рядом с B нужно размещать именно A?
Разница в один указатель -- это в два раза больше, чем те четыре, которые я привел в качестве примера.
Правда? А если смогу?
Ну да, ну да. Абсолютно несущественная, особенно если брать в расчет cache locality.
Простите не распарсил.
А можно встречный вопрос: вы вообще на C++ программировали?
Я не говорил о том, чтобы писать на C++ в стиле Си. Читайте внимательнее, пожалуйста.
Речь шла о том, что в C++ вы запросто можете программировать в процедурном стиле, как и на Си. Только делать это будет удобнее и надежнее. За счет, например, наличия ad-hoc полиморфизма, ссылок и отсутствия неявных преобразований из void*.
А вы понимаете разницу между ссылочными типами (reference types) и типами-значениями (value types) в языках с GC?
Если у вас в Java тип A -- это reference type, т.е.:
то когда вы делаете член типа A в классе B (который так же reference type):
то в B у вас хранится только ссылка на экземпляр A. И вы не можете повлиять на накладные расходы, связанные с хранением самого A и представлением ссылки на A внутри B.
Вы сказали вот что:
"Это по сути вообще ни о чём, на реализацию ООП в C++ уходит гораздо больше оверхеда (по сравнению с С)."
Это сложно воспринять как-то иначе как накладные расходы на ООП в C++. А так как в чистом Си ООП нет, то когда в Си нам придется использовать ООП, то мы будет делать это вручную и обойдется нам это дешевле, чем в C++.
Тогда при чем здесь ООП в C++? На C++ вы точно так же (даже надежнее и безопаснее) сможете использовать процедурный стиль, как и в Си.
Или вы в C++ видите какие-то дополнительные издержки даже на процедурный стиль в сравнении с Си?
Вы в моих словах нашли пафос? Перечитайте, пожалуйста.
С чего вы взяли, что речь идет о счетчиках ссылок?
Ручное управление памятью (по крайней мере в моем мире) -- это не только ручной вызов new/delete (или malloc/calloc/free), и даже не деление на стек/хип. Это еще и использование union-ов, пулы/арены памяти и placement new. А так же агрегирование данных, когда вы объект класса A можете сделать полем класса B и память для A будет частью памяти для B (тогда как в языках с GC если у вас A -- это ссылочный тип, то частью другого ссылочного типа B вы его не сделаете).
Зная как вы не можете в обоснование собственных утвержений я даже и не стал заострять внимание вот на этом: "на реализацию ООП в C++ уходит гораздо больше оверхеда (по сравнению с С)". Но раз вы сами завели эту шарманку, то может поделитесь цифрами о том, насколько рукопашная реализация ООП на чистом Си выгоднее, чем поддерживаемая компилятором и рантаймом в С++?
Наверное, я чего-то не понимаю в программировании, но когда половина времени уходит не на полезную работу, а на менеджмент памяти, то в этом нет ничего хорошего. А когда это еще и характеризуют как "по сути ни о чём", то такое ощущение, что не понимаю я вообще ничего.
Либо работа с большими объемами данных, где экономия 4-х байт на каждый объект приводит к снижению потребления памяти на сотни мегабайт. А с учетом того, что быстрые кэши маленькие, а загрузка в них данных из ОП медленная, то экономия на потребляемых объемах как-то сама собой трансформируется в выигрыш по скорости.
Ну да, ну да. ООП было, а слова такого не было, ага.
То, что Алан Кей хорош в самовосхвалении не означает, что ООП -- это только то, что вышло из SmallTalk и имеет отношение к SmallTalk.
Но даже это не важно. Вы сослались на SmallTalk, но так и не объяснили почему для полиморфизма нужна динамическая типизация.
И вряд ли это у вас получится, т.к. полиморфизм бывает разный. И, сюрприз, C++ поддерживает несколько их видов. Можно выбирать на вкус.
Конкретно в C++ ООП и его терминология пришли из Simula 67, который появился за несколько лет до начала работ над SmallTalk-ом.
Вы так говорите, как будто компилятору позволено так поступать с корректной программой. А для того, чтобы написать корректную программу вовсе не обязательно упарываться изучением ассемблерного выхлопа. Скорее даже наоборот.