All streams
Search
Write a publication
Pull to refresh
82
0.1
Евгений Охотников @eao197

Велосипедостроитель, программист-камикадзе

Send message

Повторю вопрос специально для вас: "какие накладные расходы на ООП есть, например, у 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++

Отучаемся говорить за всех (c)

Не в секундах?

И даже не в минутах.

Именно потому, что в Си ООП нет, то накладные расходы на ООП в Си равны нулю.

Да, да, да. Поэтому когда в каком-нибудь Си-шном проекте, типа OpenSSL, потребуются аналоги виртуальных функций, которые колхозятся на структурах с указателями на функции, то это все абсолютно бесплатно. Ага.

Но я этого, конечно, не имел в виду.

Вот и приходится выяснять что же вы имели в виду.

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

А имел в виду, что, программируя на С++, мы будем вынуждены, в отличие от Си, использовать реализацию ООП, так как на ООП построены библиотеки С++ и практика программирования на С++.

Тут бы очень хотелось выяснить кто такие "мы".

А практика программирования на C++ уже давным-давно (лет 25 минимум, а то и все 30) держится на мультипарадигменности, где ООП соседствует как с обычным процедурным подходом, так и с обобщенным программированием.

Я писал, что накладные расходы C++ возникают именно из-за поддержки ООП

Уже несколько раз цитировал что именно вы написали, повторяться не буду. Просто еще раз напомню, что рассуждать о накладных расходах на что-то по сравнению с чем-то можно только в случае, если это "что-то" есть в том самом "чем-то". В Си ООП нет, поэтому оценивать накладные расходы C++ на ООП в сравнении с Си бессмысленно. Не удивительно, что фактически подтвердить свои утверждения вы не можете.

Прекрасно, начиналось все с

на реализацию ООП в C++ уходит гораздо больше оверхеда (по сравнению с С)

а закончилось общими фразами

нет выраженной корреляции быстродействия реально используемых программ с языком, на котором они написаны

Да вы просто мастер аргументировать вами же высказанные утверждения.

Тормозных программ на C++ столько же в процентном отношении, как и на других языках.

Только вот тормозят C++ программы несколько не так, чем программы на Ruby, например.

А я и не аргументировал в пользу 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, то зачем тогда 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-х байт на каждый объект приводит к снижению потребления памяти на сотни мегабайт. А с учетом того, что быстрые кэши маленькие, а загрузка в них данных из ОП медленная, то экономия на потребляемых объемах как-то сама собой трансформируется в выигрыш по скорости.

Ну да, ну да. ООП было, а слова такого не было, ага.

То, что Алан Кей хорош в самовосхвалении не означает, что ООП -- это только то, что вышло из SmallTalk и имеет отношение к SmallTalk.

Но даже это не важно. Вы сослались на SmallTalk, но так и не объяснили почему для полиморфизма нужна динамическая типизация.

И вряд ли это у вас получится, т.к. полиморфизм бывает разный. И, сюрприз, C++ поддерживает несколько их видов. Можно выбирать на вкус.

Вообще ООП и его терминология пошли из Смоллтока.

Конкретно в C++ ООП и его терминология пришли из Simula 67, который появился за несколько лет до начала работ над SmallTalk-ом.

Вы так говорите, как будто компилятору позволено так поступать с корректной программой. А для того, чтобы написать корректную программу вовсе не обязательно упарываться изучением ассемблерного выхлопа. Скорее даже наоборот.

Information

Rating
3,739-th
Location
Гомель, Гомельская обл., Беларусь
Registered
Activity