Здравствуйте, so5team, Вы писали:
s> ·>Иди туда, спроектируй всё по правильному — заработаешь миллионы и получишь мировую известность. s> Не-не-не, у меня с сарказмом все нормально, в отличии от.
Прошу прощения, не распознал.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Насколько я понимаю, они делали простые контейнеры вроде vector/list так, чтобы после оптимизации получался предельно эффективный код, не уступающий коду со встроенными массивами и ручными списками. В принципе, это правильно, иначе нареканий на STL было бы гораздо больше.
т.е. виртуальные итераторы и методы добавления/удаления элементов как это сделано в C# и Java, добавляют таки существенные накладные расходы, что разработчики STL от этого отказались?
Здравствуйте, so5team, Вы писали:
S>Вроде бы об этом Страуструп в своей книге "Дизайн и эволюция" писал. Как и об отсутствии единого базового класса Object, как в во многих ООЯП.
Если мне не изменяет память, то разработчики STL максимально упарывались по производительности и потреблению памяти, чтобы работало и на утюгах.
S>Это какой-то странный код, если ему фиолетово, используется ли std::vector или std::set.
Допустим, нужно сохранить коллекцию в json в виде массива [1,2,3] или что-то в этом духе.
Методу записи просто нужно перебрать все элементы коллекции, получить их значения и записать в json. Вектор там или множество — вообще же без разницы.
При чтении значений из json мне так же без разницы как там элементы хранятся, просто нужно их по очереди добавить в коллекцию.
Здравствуйте, karbofos42, Вы писали:
S>>Вроде бы об этом Страуструп в своей книге "Дизайн и эволюция" писал. Как и об отсутствии единого базового класса Object, как в во многих ООЯП.
K>Если мне не изменяет память, то разработчики STL максимально упарывались по производительности и потреблению памяти, чтобы работало и на утюгах.
Чтобы работал на утюгах -- это про проект Oak, из которого затем получился костыль под названием Java 1.0. Этот костыль затем в течении 10 лет дорабатывали чтобы он сравнялся по выразительности с C++ времен 1994-го года.
В C++ же идеология "не платишь за то что не используешь"(1)
Поэтому если программисту не нужен базовый Object, то значит его не должно быть и вовсе.
S>>Это какой-то странный код, если ему фиолетово, используется ли std::vector или std::set.
K>Допустим, нужно сохранить коллекцию в json в виде массива [1,2,3] или что-то в этом духе. K>Методу записи просто нужно перебрать все элементы коллекции, получить их значения и записать в json. Вектор там или множество — вообще же без разницы. K>При чтении значений из json мне так же без разницы как там элементы хранятся, просто нужно их по очереди добавить в коллекцию.
Игрушечных примеров можно множество придумать, к практике это не будет иметь отношения. Т.к. на практике есть большая разница между непрерывным блоком с дешевой прямой индексацией и древовидной структурой из самостоятельных объектов.
-----
(1) С некоторыми поправками "на ветер" и специфичность восприятия как "не используешь", так и "не платишь".
Здравствуйте, karbofos42, Вы писали:
K>Можно у разработчиков STL спросить почему они не сделали абстракции в виде Collection/ICollection как в библиотеках той же Java или C#.
Это потребует дополнительного расхода памяти размером в один указатель на объект, что противоречит известному принципу про платёж.
K>Удобно ведь было бы в метод принимать просто коллекцию, получать какой-то абстрактный итератор для перебора или через виртуальный метод add добавить пару элементов. K>Вместо этого приходится писать методы конкретно под std::vector и никакой std::set не передашь.
Перебор можно сделать через шаблонные функции, а вот добавление — не факт, что оно должно быть универсальным.
Впрочем, что мешает написать обёртку, которая будет принимать в конструкторе тип контейнера (или сам контейнер) и выставлять желаемый интерфейс? Такое можно написать за несколько часов без особого труда.
Однако, ICollection всё равно не получится сделать один на всех, ведь контейнеры шаблонные, а значит ICollection тоже будет шаблонным, т.е. ICollection<int> и ICollection<char> — это два разных типа.
Всё это из-за того, что в С++ до сих пор не добавили шаблонные виртуальные функции.
Здравствуйте, so5team, Вы писали:
S>Игрушечных примеров можно множество придумать, к практике это не будет иметь отношения. Т.к. на практике есть большая разница между непрерывным блоком с дешевой прямой индексацией и древовидной структурой из самостоятельных объектов.
На практике не пишут в json и не перебирают коллекции?
Итераторы вроде бы для этого и придумали, чтобы они умели оптимально по соответствующим структурам ходить.
Зачем тогда в стандарт добавили цикл for для диапазонов?
Если я через шаблон или вручную продублирую метод для std::vector и std::set, где будет в итоге одинаковый цикл "for (auto& v: values)", то это нормально?
Или для vector и set нельзя одинаковый перебор использовать?
Здравствуйте, B0FEE664, Вы писали:
BFE>Перебор можно сделать через шаблонные функции, а вот добавление — не факт, что оно должно быть универсальным. BFE>Впрочем, что мешает написать обёртку, которая будет принимать в конструкторе тип контейнера (или сам контейнер) и выставлять желаемый интерфейс? Такое можно написать за несколько часов без особого труда.
Да вроде уже готовое есть — inserter/back_inserter
Здравствуйте, karbofos42, Вы писали:
K>На практике не пишут в json
Пишут. Но либо не парятся о том, что лежит под капотом у конкретной json-библиотеки (а авторы этой библиотеки не мечутся между vector или set), либо заморачиваются тем, как и где хранится очередная часть json-а (и тут тоже нет метаний между vector и set).
K>и не перебирают коллекции?
Для перебора коллекций отлично работают шаблоны. Уже много лет как.
А если кому-то нужно спрятать тип коллекции за каким-то непрозрачным фасадом, то это делается обычными классами с виртуальными методами в конкретном проекте. Без надобности вводить ICollection в стандартную библиотеку C++.
Принцип "не платим за то, что не используем" (при всех его оговорках) работает именно так.
Здравствуйте, karbofos42, Вы писали:
k> т.е. виртуальные итераторы и методы добавления/удаления элементов как это сделано в C# и Java, добавляют таки существенные накладные расходы, что разработчики STL от этого отказались?
В этих яп есть gc и другие штуки, которые без инфы о типе в рантайме работать не могут. Поэтому это просто другой компромисс, вместо нулевых накладных расходов добавляются несколько вкусных вещей, как "бесплатность" виртуальных функций, gc и прочий jit и reflection.
Здравствуйте, ·, Вы писали:
·>Какой-нибудь там Order будет i64 цена, i64 количество, i16 currency pair, и неск байт всяких атрибутов. И в памяти лежат миллионы таких.
Здравствуйте, B0FEE664, Вы писали:
BFE>Это потребует дополнительного расхода памяти размером в один указатель на объект, что противоречит известному принципу про платёж.
т.е. ТС не прав про гуманитариев, виртуальные методы создают большие накладные расходы и на них действительно имеет смысл экономить?
BFE>Впрочем, что мешает написать обёртку, которая будет принимать в конструкторе тип контейнера (или сам контейнер) и выставлять желаемый интерфейс? Такое можно написать за несколько часов без особого труда.
В итоге в проекте будет какой-то зоопарк, а накладных расходов ещё больше, чем было бы с виртуальными методами изначально.
Хотя в плюсах наверно так принято, чтобы веселее было. Один интерфейс как в других языках — не интересно, а вот когда где-то vector, где-то QList или wxVector или ещё какой подобный класс — это весело и замечательно, особенно когда нужно из одного типа в другой данные гонять, т.к. у тебя есть vector, а нужный метод написан для QList.
BFE>Однако, ICollection всё равно не получится сделать один на всех, ведь контейнеры шаблонные, а значит ICollection тоже будет шаблонным, т.е. ICollection<int> и ICollection<char> — это два разных типа. BFE>Всё это из-за того, что в С++ до сих пор не добавили шаблонные виртуальные функции.
так и пусть разные будут, лишь бы можно было в итоге написать без шаблонов и обёрток метод вида:
и передать туда и std::vector<int> и std::set<int> и QList<int> (при условии конечно, что все они унаследуются от collection<int>)
Или всё же такое наследование и последующие виртуальные вызовы добавят увеличение потребления памяти, существенно снизит скорость работы и в плюсах так не принято?
Здравствуйте, karbofos42, Вы писали:
K>т.е. виртуальные итераторы и методы добавления/удаления элементов как это сделано в C# и Java, добавляют таки существенные накладные расходы, что разработчики STL от этого отказались?
Я, честно говоря, хз. Возможно, дело в том, что добавление возможности вызова виртуального итератора в базовый контейнер сразу же заметно добавляет накладных расходов для простейших контейнеров, а сделать такие шаблоны, чтоб эта возможность добавлялась без ненужных хвостов, не получилось. Ну, или просто не захотели.
Здравствуйте, ·, Вы писали:
·>В этих яп есть gc и другие штуки, которые без инфы о типе в рантайме работать не могут. Поэтому это просто другой компромисс, вместо нулевых накладных расходов добавляются несколько вкусных вещей, как "бесплатность" виртуальных функций, gc и прочий jit и reflection.
Не понимаю как тут gc и прочее помогают. Виртуальные методы и в C# и Java вызываются медленнее, чем "обычные", т.е. просто в этих языках решили, что общие интерфейсы коллекций с последующей виртуализацией — это адекватная плата за удобство (кому нужно — может всегда написать свою более оптимальную коллекцию). В C++ предпочли экономию по максимуму и не выводить стандартных интерфейсов для тех же коллекций.
Здравствуйте, so5team, Вы писали:
S>Ну так в HFT же криворукие идиоты работают, половину которых набрали по объявлению, а вторую половину -- по блату.
Зачем же именно так? Я уже говорил, что среди использующих C++ очень мало тех, кто уделяет внимание таким мелочам, как десятки байт или микросекунды. В преподавании C++ уже очень давно преобладает подход "сверху", когда основной упор делается на абстракции, обобщенные контейнеры и алгоритмы, а "снизу" язык чаще изучают лишь по собственной инициативе, и только те, кому это реально интересно.
Поэтому там, где нужна предельная эффективность, до сих пор преобладают сишники. А плюсовики, изучавшие язык "сверху", вполне могут долгое время сохранять усвоенные когда-то предубеждения, что не мешает им писать достаточно эффективный код способами, которым они доверяют.
Здравствуйте, Евгений Музыченко, Вы писали:
S>>Ну так в HFT же криворукие идиоты работают, половину которых набрали по объявлению, а вторую половину -- по блату.
ЕМ>Зачем же именно так?
Потому что ваша ограниченность и гуманитарность уже подбешивает как тупизм Shmj. И ведь кто-то видит у вас репутацию "опытного разработчика"
ЕМ>Я уже говорил, что среди использующих C++ очень мало тех, кто уделяет внимание таким мелочам, как десятки байт или микросекунды.
Особенно их мало среди тех, кто занимается HFT. Ну и HPC заодно, чтобы два раза не вставать.
На всякий случай для предшествующего предложения тег:
ЕМ>В преподавании C++ уже очень давно преобладает подход "сверху", когда основной упор делается на абстракции, обобщенные контейнеры и алгоритмы, а "снизу" язык чаще изучают лишь по собственной инициативе, и только те, кому это реально интересно.
На какой выборке вы делаете это заключение?
ЕМ>Поэтому там, где нужна предельная эффективность, до сих пор преобладают сишники.
Здравствуйте, karbofos42, Вы писали:
k> ·>В этих яп есть gc и другие штуки, которые без инфы о типе в рантайме работать не могут. Поэтому это просто другой компромисс, вместо нулевых накладных расходов добавляются несколько вкусных вещей, как "бесплатность" виртуальных функций, gc и прочий jit и reflection. k> Не понимаю как тут gc и прочее помогают.
Я имел в виду, не то что gc помогает, а то что накладные расходы в виде указателя на тип нужны не эксклюзивно для виртуальных вызовов, но и для gc и ещё кучи фич.
k> Виртуальные методы и в C# и Java вызываются медленнее, чем "обычные", т.е. просто в этих языках решили, что общие интерфейсы коллекций с последующей виртуализацией — это адекватная плата за удобство (кому нужно — может всегда написать свою более оптимальную коллекцию).
В этих яп добавление интерфейса дополнительных расходов не добавит, т.к. инфа о типе уже есть. Иными словами, если выкинуть ICollection — станет только хуже.
k> В C++ предпочли экономию по максимуму и не выводить стандартных интерфейсов для тех же коллекций.
Потому что если просто ввести интерфейс, придётся добавить инфу о типе. Игра не стоит свеч.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ> ·>Какой-нибудь там Order будет i64 цена, i64 количество, i16 currency pair, и неск байт всяких атрибутов. И в памяти лежат миллионы таких. ЕМ> А виртуальные функции сюда каким боком?
Если проектировать "красиво", то удобнее будет иметь несколько типов, в зависимости от вида ордера (market/limit/stop/etc), т.к. они могут работать несколько по-разному. Всякий диспатчинг, однако, делают по битовым атрибутам и if/else/switch вместо виртуальных ф-ций.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я, честно говоря, хз. Возможно, дело в том, что добавление возможности вызова виртуального итератора в базовый контейнер сразу же заметно добавляет накладных расходов для простейших контейнеров, а сделать такие шаблоны, чтоб эта возможность добавлялась без ненужных хвостов, не получилось. Ну, или просто не захотели.
По-моему это идеология языка. Людям нравится городить хитрые оптимизации и вот так забавляются.
В других языках просто выбрали удобство за счёт небольшой платы. В С++ и в стандартных библиотеках на тех же виртуальных вызовах экономят, что закономерно идёт как рекомендация.
Я помню ещё холивары на счёт исключений. Одни писали, что этот механизм крутой и удобный. Другие топили за коды ошибок, т.к. исключение — это же создание объекта и прочие непозволительно дорогие накладные расходы.
На мой взгляд для большинства софта подобная экономия на спичках (виртуальных методах) вообще незаметна. Но если по такому не упарываться, то непонятно зачем на C++ писать, а не взять что-то более удобное
Здравствуйте, ·, Вы писали:
·>Если проектировать "красиво", то удобнее будет иметь несколько типов, в зависимости от вида ордера (market/limit/stop/etc), т.к. они могут работать несколько по-разному. Всякий диспатчинг, однако, делают по битовым атрибутам и if/else/switch вместо виртуальных ф-ций.
В такой ситуации в полный рост встает вопрос о разнесении разных типов по собственным контейнерам, чтобы вынести проверку типа как можно выше. Но это, понятно, только после измерений на конкретных задачах.