Одесса: 6°С (вода 8°С)
Киев: 2°С
Львов: -1°С

Тема: C++ haters handbook :-)

Ответить в теме
Страница 1 из 8 1 2 3 ... ПоследняяПоследняя
Показано с 1 по 20 из 157
  1. Вверх #1

    Post C++ haters handbook :-)

    прошу модераторов перенести сюда ветку из топика C++ vs Java начиная с поста 88
    The future is already here - it is just unevenly distributed. (c) W. Gibson


  2. Вверх #2
    Частый гость Аватар для THRESHE
    Пол
    Мужской
    Адрес
    Одесса
    Сообщений
    985
    Репутация
    39
    Мдя никогда не думал что будут сравнивать С и С++

    На С все равно ничего большого не напишешь.
    2 homo ludens и чем же С лучше чем С++ ?

  3. Вверх #3
    Цитата Сообщение от pal
    крайне любопытно посмотреть на пример не нооп абстракций, в котором совсем ничего не пробрасывается между уровнями. все упирается в то, каким данным это разрешить, а каким - нет, т.е. в дизайн интерфейсов
    практический любой правильный С-интерфейс. Правильные С-интерфейсы можно легко найти в glibc и сопутствующих продуктах. Возьмите например POSIX threads (pthread_t).

    давайте напишем интерфейс на С объекта transglukator.

    что мы имеем на С
    два h-файла.
    transglukator.h
    transglukator_int.h
    transglukator.c

    ******* в transglukator.h
    typedef что-то transglukator_t.
    //что-то обычно либо void* либо int
    //в обоих случаях это хендл с неизвестной снаружи внутренней структурой.

    transglukator_t transglukator_init(...);
    int transglukator_destroy(transglukator_t);

    ******* в transglukator_int.h

    typedef struct
    {
    ... internal representation of
    } transglukator_int_t;

    // плюс внутренние структуры, никому не интересные снаружи, но которые могут зависеть от других библиотек и h-файлов

    ******* в transglukator_int.c
    #include "transglukator.h"
    #include "bukazoid.h"
    #include "transglukator_int.h"

    // реализация

    что бы мы имели на С++ в худшем варианте

    ******* в transglukator.h
    class transglukator
    {
    public:
    transglukator(...);
    ~transglukator(void)
    private:
    ....
    };

    ******* в transglukator.с

    transglukator::transglukator(...)
    {
    ...
    }

    transglukator::~transglukator(void)
    {
    ...
    }

    ...

    чем хуже реализация С++?

    а вот чем.
    мы можем зафиксировать на начальном этапе проекта интерфейсы. Но мы не можем зафиксировать реализации. Появление в private скрытой внутренней переменной вызывает полную перекомпиляцию проекта использующего transglukator.
    В С-реализации требуется только перелинковка, более того, если вы пишете сервер, работающий 365x24x7 то даже этого не надо - выносите код трансглюкатора в dll и перегружаете ее не останавливая сервера.
    Второй минус. Если для внутренней реализации трансглюкатора требуется определение класса bukazoid, то это автоматически означает, что все определения класса буказоид и все его интерфейсы включаются в путь h-файлов (это к тому, почему я никогда не пользую std::abs - посмотрите сколько мусора он за собой тянет). Время компиляции возрастает офигенно. Связность исходников - до упора.
    Можно выкрутиться двумя трюками.
    1. написать псевдоадаптер - пустой класс-оболочку только с вызовами другого класса. без динамических переменных это обычно сложно. Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки, а псевдоадаптер - это файл. Читаемость кода при этом тоже не повышается. Зато повышается его связность.
    Кстати для темплейтов эта практика просто необходима, нормально реализованный шаблон - это только интерфейсы к единой для всех его реализаций библиотеке.
    Как вы думаете, почему stl написан на С?
    2. напрямую использовать С-шные методы описанные выше.
    метод с хендлом типа int (юзается когда надо поддерживать целостность коллекции трансглюкаторов) работает. А вот с void* иногда бывают проблемы.
    Почему? А потому что умники из комитетов по религиозно-объектной чистоте постановили - void* должен явно преобразовываться к типу. Одним этим выстрелом они убили много зайцев - один из которых - уничтожение обратной совместимости с С. Неслабо, да?

    Цитата Сообщение от pal
    правильно ли я понимаю, что функциональность шире, чем у ассемблера, невозможна ?
    Возможна конечно, хотя с частичной потерей эффективности. Почему нет? Просто абстракции должны иметь поменьше дырок. Более того, потеря функциональности тоже возможна, но функциональность не должна подменяться удобством. Это абсолютно разные вещи. try/catch не расширяет функциональность, также как и uBlas. Иначе мы получаем то что имеем - из случайно выбранных 10 проектов на sf.net 9 будут просто оболочками-адаптерами к чужому коду, оболочками с нулевой функциональностью, но удобным (не для всех) интерфейсом. Удобство - категория субъективная, а функциональность - нет. Вот и весь критерий.

    продолжаем? я еще не на все вопросы ответил...
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  4. Вверх #4
    если у тебя интерфейс предназначен для взаимодействия с другими компонентеми - его проектируют как чисто интерфейсный и скрывают реализацию

    говорить о том что на макросах проще построить скрытие реализации чем на с++ или на той же java - это притягивать за уши



    Цитата Сообщение от homo ludens Посмотреть сообщение
    практический любой правильный а вот чем.
    мы можем зафиксировать на начальном этапе проекта интерфейсы. Но мы не можем зафиксировать реализации. Появление в private скрытой внутренней переменной вызывает полную перекомпиляцию проекта использующего transglukator.
    В С-реализации требуется только перелинковка, более того, если вы пишете сервер, работающий 365x24x7 то даже этого не надо - выносите код трансглюкатора в dll и перегружаете ее не останавливая сервера.
    Второй минус. Если для внутренней реализации трансглюкатора требуется определение класса bukazoid, то это автоматически означает, что все определения класса буказоид и все его интерфейсы включаются в путь h-файлов (это к тому, почему я никогда не пользую std::abs - посмотрите сколько мусора он за собой тянет). Время компиляции возрастает офигенно. Связность исходников - до упора.
    продолжаем? я еще не на все вопросы ответил...

  5. Вверх #5
    Цитата Сообщение от TechInsightJobs Посмотреть сообщение
    если у тебя интерфейс предназначен для взаимодействия с другими компонентеми - его проектируют как чисто интерфейсный и скрывают реализацию

    говорить о том что на макросах проще построить скрытие реализации чем на с++ или на той же java - это притягивать за уши
    я нигде в своем посте не писал о макросах.
    я писал о разделении уровней и понижении связности кода. Макросы в этом примере не используются нигде.
    То, что проектировать интерфейс надо правильно - банальность. Но на С++ почему-то редко так делают. Ваш вариант проектирования - это трюк 1-го типа из перечисленных в списке. Который полностью совпадает с С-реализацией если после typdef поставить скобки class transglukator { public: ..... };

    А вот практический пример такой реализации.

    ******************* C++ x.cc
    #include <algorithm>

    int main(void)
    {
    int x=-1;
    return std::abs(x);
    }

    ******************* C y.c
    #include <math.h>

    int main(void)
    {
    int x=-1;
    return labs(x);
    }

    казалось бы - какая разница?

    а вот какая
    gcc -E x.cc | wc -l
    15280
    gcc -E y.c | wc -l
    663

    нафига мне для std::abs итераторы? Которые включаются в общий обход h-файлов.
    Какое будет время компиляции для проекта из 100к строк?
    350 килобайт текста! Чтобы вычислить abs?
    А это стандартная библиотека. Заглянем в boost?

    Ладно, это компилятор. Фиг с ним, а что будет при
    gcc -S x.cc ; wc -l <x.s
    42
    gcc -S y.c ; wc -l <y.s
    27

    Справедливости ради замечу, что исполняемый код практически одинаков, вся разница в добавлении ссылок на pthread. Но на хрена они тут нужны, мне совершенно непонятно.

    причем это системная библиотека с гарантированно стабильным интерфейсом. А что будет в reallife?
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  6. Вверх #6
    "Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки,"

    а механизм абстрактных классов и виртуальные функции это встроенные средства языка

    про правильное проектирование на с++ - это делают гораздо чаще чем на с
    думаю дизайн документов для с++ проектов гораздо больше чем для С

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




    Цитата Сообщение от homo ludens Посмотреть сообщение
    я нигде в своем посте не писал о макросах.
    я писал о разделении уровней и понижении связности кода. Макросы в этом примере не используются нигде.
    То, что проектировать интерфейс надо правильно - банальность. Но на С++ почему-то редко так делают. Ваш вариант проектирования - это трюк 1-го типа из перечисленных в списке. Который полностью совпадает с С-реализацией если после typdef поставить скобки class transglukator { public: ..... };

    А вот практический пример такой реализации.

    ******************* C++ x.cc
    #include <algorithm>

    int main(void)
    {
    int x=-1;
    return std::abs(x);
    }

    ******************* C y.c
    #include <math.h>

    int main(void)
    {
    int x=-1;
    return labs(x);
    }

    казалось бы - какая разница?

    а вот какая
    gcc -E x.cc | wc -l
    15280
    gcc -E y.c | wc -l
    663

    нафига мне для std::abs итераторы? Которые включаются в общий обход h-файлов.
    Какое будет время компиляции для проекта из 100к строк?
    350 килобайт текста! Чтобы вычислить abs?
    А это стандартная библиотека. Заглянем в boost?

    Ладно, это компилятор. Фиг с ним, а что будет при
    gcc -S x.cc ; wc -l <x.s
    42
    gcc -S y.c ; wc -l <y.s
    27

    Справедливости ради замечу, что исполняемый код практически одинаков, вся разница в добавлении ссылок на pthread. Но на хрена они тут нужны, мне совершенно непонятно.

    причем это системная библиотека с гарантированно стабильным интерфейсом. А что будет в reallife?

  7. Вверх #7
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    чем хуже реализация С++?

    а вот чем.
    мы ведь не будем ставить в упрек с++ плохость вашей реализации на нем ?
    (это к тому, почему я никогда не пользую std::abs - посмотрите сколько мусора он за собой тянет).
    вы его не используете по другой причине: вы не знаете, что он определен в <cmath>, а не в <algorithm>
    1. написать псевдоадаптер - пустой класс-оболочку только с вызовами другого класса. без динамических переменных это обычно сложно. Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки, а псевдоадаптер - это файл. Читаемость кода при этом тоже не повышается. Зато повышается его связность.
    если речь об идиоме pimpl, то ее используют с несколько более широкими целями. можно реализовать value semantics, что вообще невозможно на с, на худой конец, можно удостовериться что обьект будет правильно разрушен.
    у вас же в случае void * его можно удалить free с потерей всех остальных ресурсов, либо в случае int можно делать очень много других ненужных операций, а в конце все равно не удалить
    при желании на с++ можно делать точно так же, как и на с:
    class A; A * f ( ); void g ( A * ); ...
    в качестве дополнительного бонуса вы не передадите его функции, которая ждет тоже void * или int, но на самом деле совсем другой, также delete на неопределенный класс будет ругаться ( помните, я говорил не использовать malloc/free ? ). только так делать не надо, потому что кто-то обязательно забудет его удалить.
    еще можно использовать абстрактный базовый класс и возвращать smartpointer на конкретную реализацию, если вам не жалко виртуальных функций.

    как мы видим, на с++ можно сделать точно так же, только лучше, а можно слегка по другому, но еще лучше
    Кстати для темплейтов эта практика просто необходима, нормально реализованный шаблон - это только интерфейсы к единой для всех его реализаций библиотеке.
    Как вы думаете, почему stl написан на С?
    я знаю, что он написан на с++. где вы такое видели ?
    вы, похоже, шаблоны с чем-то другим перепутали
    2. напрямую использовать С-шные методы описанные выше.
    как я уже показал, так делать нельзя и не надо никогда
    метод с хендлом типа int (юзается когда надо поддерживать целостность коллекции трансглюкаторов) работает. А вот с void* иногда бывают проблемы.
    Почему? А потому что умники из комитетов по религиозно-объектной чистоте постановили - void* должен явно преобразовываться к типу. Одним этим выстрелом они убили много зайцев - один из которых - уничтожение обратной совместимости с С. Неслабо, да?
    учитывая, что к void * преобразовывается автоматом, разрешение обратного преобразования одним махом сводит на нет всю систему типов - любой тип автоматически превращается в любой другой через void *.
    может, вам просто ближе к сердцу языки с динамической типизацией и рантайм проверками ? это не стыкуется с вашей обеспокоенностью эффективностью исполнения.

    так же нет никакой проблемы в этой несовместимости с с. разве, что вы захотите перевести программу с с на с++. тогда надо радоваться, заодно несколько ошибок вокруг void* обнаружите
    Возможна конечно, хотя с частичной потерей эффективности. Почему нет? Просто абстракции должны иметь поменьше дырок.
    с этим трудно не согласиться, но как вы из этого сделали вывод, что абстракций быть не должно ?
    Более того, потеря функциональности тоже возможна, но функциональность не должна подменяться удобством. Это абсолютно разные вещи. try/catch не расширяет функциональность, также как и uBlas. Иначе мы получаем то что имеем - из случайно выбранных 10 проектов на sf.net 9 будут просто оболочками-адаптерами к чужому коду, оболочками с нулевой функциональностью, но удобным (не для всех) интерфейсом. Удобство - категория субъективная, а функциональность - нет. Вот и весь критерий.
    я не могу разобраться в вашей терминологии. чем отличается функциональность от удобства, если преимуществом с по сравнению с ассемблером является функциональность, а преимуществом с++ по сравнению с с - удобство ? или у вас есть с, который каким-то сверхъестественным образом выполняется процессором телепатически с большей функциональностью, чем ассемблер ?

  8. Вверх #8
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки, а псевдоадаптер - это файл
    попробуйте на досуге найти в /usr/include/c++/4.1.*/tr1/ реализацию std::tr1::bind. а там даже goto в макросах нет
    но это все мелочи по сравнению с тем, что бывает когда кто-то переопределяет malloc/free/realloc, и при этом обменивается указателями с модулями, где ничего такого не переопределено.

  9. Вверх #9
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Правильные С-интерфейсы можно легко найти в glibc и сопутствующих продуктах. Возьмите например POSIX threads (pthread_t).
    я боюсь, что вы выбрали не совсем правильный интерфейс
    на весь bits/pthreadtypes.h целых 4 инта: pthread_t, pthread_key_t, pthread_once_t, pthread_spinlock_t
    знаете, почему ? потому что они и являются интами
    остальные типы делятся на две группы:
    typedef union
    {
    struct
    {
    int __lock;
    unsigned int __futex;
    __extension__ unsigned long long int __total_seq;
    __extension__ unsigned long long int __wakeup_seq;
    __extension__ unsigned long long int __woken_seq;
    void *__mutex;
    unsigned int __nwaiters;
    unsigned int __broadcast_seq;
    } __data;
    char __size[__SIZEOF_PTHREAD_COND_T];
    __extension__ long long int __align;
    } pthread_cond_t;

    typedef union
    {
    char __size[__SIZEOF_PTHREAD_CONDATTR_T];
    int __align;
    } pthread_condattr_t;

  10. Вверх #10
    Цитата Сообщение от pal Посмотреть сообщение
    мы ведь не будем ставить в упрек с++ плохость вашей реализации на нем ?
    Я ведь сразу сказал, что это худший вариант.
    Однако куча программеров так пишет. Более того для многих junior'ов это нормальный код. :- (

    Цитата Сообщение от pal Посмотреть сообщение
    вы его не используете по другой причине: вы не знаете, что он определен в <cmath>, а не в <algorithm>
    потому что с <cmath> у меня это вообще не компилится. Бедный компилятор не может выбрать какую из перегруженных функций ему выполнять - float, double или long double.

    Цитата Сообщение от pal Посмотреть сообщение
    у вас же в случае void * его можно удалить free с потерей всех остальных ресурсов, либо в случае int можно делать очень много других ненужных операций, а в конце все равно не удалить ; )
    Удалять его free никому в голову не придет. А насчет забыть - так для динамически определяемой памяти это верно и для С++. Не юзать динамическую память без обверток?
    Вы с windows handle тоже делаете много ненужных вещей?
    Идея в том, что обычно transglukator_t появляется только в вызовах функций собственного интерфейса. Или в промежуточных переменных. Никому в голову не придет допустим складывать объекты этого типа. Кроме программиста С++ привычного к перегрузкам операторов. : -)
    Цитата Сообщение от pal Посмотреть сообщение
    как мы видим, на с++ можно сделать точно так же, только лучше, а можно слегка по другому, но еще лучше
    На С++ это можно сделать сложнее и единственный плюс, который я здесь вижу - контроль типов, который таки да полезен, когда мы его действительно хотим видеть. И вреден, когда мы его не хотим видеть.
    Кроме того, кто-то из известных программистов сказал очень умную вещь - хороший язык, это тот, в котором правильную вещь можно сделать единственным способом.
    А я добавлю от себя - правильная реализация в хорошем языке должна отличаться от неправильных тем, что имеет самый компактный и элегантный интерфейс, тем самым создавая общую эстетику для групп программистов и облегчая взаимное понимание кода.
    В С++ эти правила не выполняются.
    Есть правда пару нюансов с наследованием, но имхо в правильной программе наследование должно юзаться реже чем longjump.

    Цитата Сообщение от pal Посмотреть сообщение
    я знаю, что он написан на с++. где вы такое видели ?
    вы, похоже, шаблоны с чем-то другим перепутали
    Изначально библиотека писалась на С. Потом была переделана на С++, но внутри это выглядело как C+generic programmig, разобраться там было достаточно сложно, код сверхсвязный. Впрочем внутри я рассматривал раниие реализации от HP и достаточно давно. Однако в википедии написано вот что.

    Careless use of STL templates can lead to code bloat. This has been countered with special techniques within STL implementation (using void* containers internally) and by improving optimization techniques used by compilers.
    Я тоже не представляю себе эффективной реализации контейнеров по другому как в виде объектных интерфейсов к void* контейнерам. Возможно вы меня просветите.

    Цитата Сообщение от pal Посмотреть сообщение
    так же нет никакой проблемы в этой несовместимости с с. разве, что вы захотите перевести программу с с на с++. тогда надо радоваться, заодно несколько ошибок вокруг void* обнаружите
    С-программа не компилируется в общем случае на С++. Предупреждение о конверсии void* можно было сделать warning'ом. Тогда бы этих проблем не было бы и все были бы довольны.
    Цитата Сообщение от pal Посмотреть сообщение
    с этим трудно не согласиться, но как вы из этого сделали вывод, что абстракций быть не должно ?
    они не должны быть дырявыми либо если уж они дырявы, должна быть возможность эти дырки заткнуть. Абстракция должна давать больше чем забирать. Пример - интерфейсы файловых дескрипторов (open/close/read/write). Этот интерфейс очень абстрактен, потому дыряв. Работая с устройством или с сокетом или с файлом на диске вы работаете в общей абстракции. Но когда ее не хватает - есть ioctl
    Цитата Сообщение от pal Посмотреть сообщение
    я не могу разобраться в вашей терминологии. чем отличается функциональность от удобства, если преимуществом с по сравнению с ассемблером является функциональность, а преимуществом с++ по сравнению с с - удобство ? или у вас есть с, который каким-то сверхъестественным образом выполняется процессором телепатически с большей функциональностью, чем ассемблер ?
    С более функционален, чем ассемблер. В момент появления С все операционки писались на ассемблере конкретной машины. После его появления стало возможным писать их для любой машины. Это - пример расширения функциональности. С++ такого расширения не дает. Нет прикладных задач, которые можно решить на С++ но нельзя решить на С.

    Концепция функциональности против удобства на самом деле достаточно сложна для понимания и потребует не менее страницы постов. Могу написать в свободное время.


    Цитата Сообщение от pal Посмотреть сообщение
    но это все мелочи по сравнению с тем, что бывает когда кто-то переопределяет malloc/free/realloc, и при этом обменивается указателями с модулями, где ничего такого не переопределено.
    это действительно маразм, причем фатальный. Однако в реальной жизни переопределения обычно делают либо для локальной библиотеки в период отладки, либо глобально для всего проекта (mtrace), опять таки на период отладки.

    Цитата Сообщение от pal Посмотреть сообщение
    знаете, почему ? потому что они и являются интами
    они не могут являться интами!!!
    Это дескрипторы в таблице, другой вопрос, что таблица может храниться в ядре ОС, а может обрабатываться в библиотеке. В любом случае pthread_t - это куча указателей и дескрипторов. Если файловый дескриптор POSIX интерфейса (на котором весь инет держится) - int, это же не значит, что он реально целый. Это индекс в таблице значительно более сложной, чем то, что мы видим. Нету меня здесь сырцов glibc под рукой, они ж огромные, их тянуть задолбаешься. Одни h-файлы.

    Кажется мне пора приводить примеры практических вещей, которые можно сделать на С и нельзя на С++
    : -)
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  11. Вверх #11
    Кстати эти структуры в pthread.h там тоже не зря определены. Дело в том, именно их иногда нужно инициализировать статически. А вот pthread_t статически инициализировать никому в голову не придет. Поэтому он - int.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  12. Вверх #12
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Есть правда пару нюансов с наследованием, но имхо в правильной программе наследование должно юзаться реже чем longjump.
    гы
    в принципе дальше можно уже и не диспутировать

  13. Вверх #13
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Кстати эти структуры в pthread.h там тоже не зря определены. Дело в том, именно их иногда нужно инициализировать статически. А вот pthread_t статически инициализировать никому в голову не придет. Поэтому он - int.
    вы действительно считаете, что pthread_once_t можно инициализировать как-то иначе, чем статически ?
    более того, не все из определенных структур имеют макросы для инициализации. т.е. вы не правы в обе стороны. только pthread_t на самом деле является указателем на структуру, потому что ее выделять нельзя что статически, что динамически.

  14. Вверх #14
    Цитата Сообщение от TechInsightJobs Посмотреть сообщение
    гы
    в принципе дальше можно уже и не диспутировать
    Тогда дискутируйте с монстрами ООП - это они рекомендуют вместо наследования использовать композицию везде где это можно. Есть даже такое выражение - anti-pattern yo-yo. Кажется даже в GoF это было, хотя могу ошибаться, текстов под рукой нет.
    Цитата Сообщение от pal Посмотреть сообщение
    вы действительно считаете, что pthread_once_t можно инициализировать как-то иначе, чем статически ?
    более того, не все из определенных структур имеют макросы для инициализации. т.е. вы не правы в обе стороны. только pthread_t на самом деле является указателем на структуру, потому что ее выделять нельзя что статически, что динамически.
    Инициализируются статически как раз те структуры, которые представлены не хендлами.
    Я могу написать pthread_cond_t x=PTHREAD_COND_INITIALIZER
    там как раз все макросы описаны такого типа.
    на первый взгляд как бы изящней их енумераторами сделать, но если человеку надо будет работать с членами структуры, то этот метод - комбинирует все достоинства и самый простой.
    чтобы было чем заткнуть дырки в абстракциях.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  15. Вверх #15
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    потому что с <cmath> у меня это вообще не компилится. Бедный компилятор не может выбрать какую из перегруженных функций ему выполнять - float, double или long double.
    замените компилятор
    Удалять его free никому в голову не придет.
    почему не придет ? void* так и напрашивется на free
    А насчет забыть - так для динамически определяемой памяти это верно и для С++.
    это только в максимально приближенном варианте. в случае с pimpl или с умными указателями все само удалится.
    Не юзать динамическую память без обверток?
    совершенно верно ( максимально, на сколько это возможно )
    Вы с windows handle тоже делаете много ненужных вещей?
    не пользуюсь. но любой инт можно случайно передать вместо другого инта, скажем, в функцию, получающую несколько интов. и компилятор это проглотит, не поперхнувшись. в случае же указателя на уникальный класс, будет ошибка.
    Идея в том, что обычно transglukator_t появляется только в вызовах функций собственного интерфейса. Или в промежуточных переменных. Никому в голову не придет допустим складывать объекты этого типа. Кроме программиста С++ привычного к перегрузкам операторов. : -)
    зачем же складывать. представьте, что у вас есть 10 разных подсистем, в каждой из которых будет void *.
    что помешает вызвать функцию подсистемы а с указателем от подсистемы б ?
    На С++ это можно сделать сложнее и единственный плюс, который я здесь вижу - контроль типов, который таки да полезен, когда мы его действительно хотим видеть. И вреден, когда мы его не хотим видеть.
    не хотите - в с++ есть reinterpret_cast. однако, он не произойдет вдруг, сам собой, когда его никто не ждал.
    контроль типов не просто полезен, я вообще не представляю, как без него писать программы, сложнее helloworld
    Кроме того, кто-то из известных программистов сказал очень умную вещь - хороший язык, это тот, в котором правильную вещь можно сделать единственным способом.
    А я добавлю от себя - правильная реализация в хорошем языке должна отличаться от неправильных тем, что имеет самый компактный и элегантный интерфейс, тем самым создавая общую эстетику для групп программистов и облегчая взаимное понимание кода.
    В С++ эти правила не выполняются.
    ну вот, с нашими типами, правильные реализации элегантны, а reinterpret_cast - нет. у вас есть какой-то контр-пример ?
    Есть правда пару нюансов с наследованием, но имхо в правильной программе наследование должно юзаться реже чем longjump.
    наследование, конечно, надо применять к месту, а вот longjmp в хороших программах вообще не используют.
    Изначально библиотека писалась на С. Потом была переделана на С++, но внутри это выглядело как C+generic programmig, разобраться там было достаточно сложно, код сверхсвязный.
    может все-таки, это был с++, просто это было давно и с++ тогда был немного другой ? ну и вы должны понимать, что инлайн без связности не получится
    Впрочем внутри я рассматривал раниие реализации от HP и достаточно давно.
    ну, с тех пор не только реализации, но и спецификации сильно поменялись
    Я тоже не представляю себе эффективной реализации контейнеров по другому как в виде объектных интерфейсов к void* контейнерам. Возможно вы меня просветите.
    это касается только контейнеров указателей и эффективности в терминах объема сгенерированного кода, когда вы используете много однотипных контейнеров разных типов указателей.
    это всего лишь частный случай ситуации, когда шаблон имеет много операций, не зависящих от его параметров, тогда их выделяют в нешаблонный предок, чтобы не генерить один и тот же код для шаблонов с разными параметрами.
    С-программа не компилируется в общем случае на С++.
    и не должна. достаточно иметь возможность подключать с заголовки. при особом желании в следующем стандарте с могут озаботиться о совместимости и о программистах, как уже сделали местами в с99
    Предупреждение о конверсии void* можно было сделать warning'ом. Тогда бы этих проблем не было бы и все были бы довольны.
    как я уже говорил, это будет дырой в системе типов. это все равно, что предложить warning на любое недозволенное преобразование. какой в этом смысл, если в том месте, в котором это действительно нужно ( а есть ли такое ? ), можно прописать явное приведение, которое будет бросаться в глаза.
    они не должны быть дырявыми либо если уж они дырявы, должна быть возможность эти дырки заткнуть. Абстракция должна давать больше чем забирать. Пример - интерфейсы файловых дескрипторов (open/close/read/write). Этот интерфейс очень абстрактен, потому дыряв. Работая с устройством или с сокетом или с файлом на диске вы работаете в общей абстракции. Но когда ее не хватает - есть ioctl
    интерфейс дескрипторов плох, ioctl еще хуже, но я в них вижу демонстрацию недостатков с по сравнению с с++
    С более функционален, чем ассемблер. В момент появления С все операционки писались на ассемблере конкретной машины. После его появления стало возможным писать их для любой машины. Это - пример расширения функциональности. С++ такого расширения не дает.
    да и с не дает, т.к. он не первый язык высокого уровня
    Нет прикладных задач, которые можно решить на С++ но нельзя решить на С.
    никто и не спорит. однако на с++ их решать удобнее
    это действительно маразм, причем фатальный. Однако в реальной жизни переопределения обычно делают либо для локальной библиотеки в период отладки, либо глобально для всего проекта (mtrace), опять таки на период отладки.
    проблема в том, что ни компилятор, ни линкер не смогут проследить за тем, что эта библиотека не обменивается указателями с окружающим миром. как раз с "библиотекой для отладки" я и сталкивался
    они не могут являться интами!!!
    Это дескрипторы в таблице, другой вопрос, что таблица может храниться в ядре ОС, а может обрабатываться в библиотеке. В любом случае pthread_t - это куча указателей и дескрипторов.
    pthread_t это действительно указатель на структуру, маскирующийся интом
    pthread_key_t это инт, являющийся индексом массива
    pthread_once_t это просто инт в виде флагов
    pthread_spinlock_t это тоже флаг
    Если файловый дескриптор POSIX интерфейса (на котором весь инет держится) - int, это же не значит, что он реально целый. Это индекс в таблице значительно более сложной, чем то, что мы видим. Нету меня здесь сырцов glibc под рукой, они ж огромные, их тянуть задолбаешься. Одни h-файлы.
    дескиптор это индекс, но не от хорошей жизни, а в целях безопасности. причем, он совсем не защищает программу от ее ошибки, только другие программы от злонамеренной программы.
    Кажется мне пора приводить примеры практических вещей, которые можно сделать на С и нельзя на С++
    : -)
    поддерживаю

  16. Вверх #16
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    Цитата Сообщение от homo ludens Посмотреть сообщение
    Инициализируются статически как раз те структуры, которые представлены не хендлами.
    Я могу написать pthread_cond_t x=PTHREAD_COND_INITIALIZER
    там как раз все макросы описаны такого типа.
    структур всего 9, инициализаторы имеют 3, плюс pthread_once_t, который не структура. я все-таки настаиваю на том, что его иначе, чем статически, инициализировать невозможно.

  17. Вверх #17
    Посетитель
    Пол
    Мужской
    Возраст
    39
    Сообщений
    239
    Репутация
    18
    у меня есть теория
    pthread_t - единственный скрытый указатель, потому что эту структуру клиентский код самостоятельно ( без хелперов ) размещать не имеет никакой возможности. все остальные можно размещать в стеке/статически, т.е. моментально, следовательно, при дизайне озаботились в первую очередь о скорости

  18. Вверх #18
    не думаю что мне придется с ними диспутировать по поводу частоты употребления наследования по сравнению с лонгджампами

    gof не содержит антипаттернов

    ну и если вы его упомянули - то он говорит только о том что надо наследование использовать в меру и не строить длиныых наследований

    что в той же мере относится к лонгджампами - если их рассовать не в меру то понимание у разработчика исчезнет гораздо раньше чем при длинном наследовании

    Цитата Сообщение от homo ludens Посмотреть сообщение
    Тогда дискутируйте с монстрами ООП - это они рекомендуют вместо наследования использовать композицию везде где это можно. Есть даже такое выражение - anti-pattern yo-yo. Кажется даже в GoF это было, хотя могу ошибаться, текстов под рукой нет.

  19. Вверх #19
    Цитата Сообщение от TechInsightJobs Посмотреть сообщение

    gof не содержит антипаттернов
    sorry, я сразу сказал, что исходников нет под рукой.
    атипаттерны тем не менее существуют. как и антипаттерн yo-yo.
    ИМХО GoF кажется была фраза inheritance breaks encapsulation?
    Так вот для меня encapsulation ценнее inheritance. Поэтому ценность inheritance для меня лично падает ниже логджампа.
    Кстати о лонгджампе.
    А вы никогда не использовали его с функциями типа alloca и strdupa? Он неожиданно начинает выглядеть довольно милым.
    The future is already here - it is just unevenly distributed. (c) W. Gibson

  20. Вверх #20
    Цитата Сообщение от pal Посмотреть сообщение
    замените компилятор
    на двух тачках с разными архитектурами.
    gcc version 3.4.4 20050526
    gcc version 4.1.0

    x.cc:6: error: call of overloaded 'abs(int&)' is ambiguous
    /usr/include/c++/4.1.0/cmath:89: note: candidates are: double std::abs(double)
    /usr/include/c++/4.1.0/cmath:93: note: float std::abs(float)
    /usr/include/c++/4.1.0/cmath:97: note: long double std::abs(long double)


    Цитата Сообщение от pal Посмотреть сообщение
    почему не придет ? void* так и напрашивется на free
    какой void*? человек видит transglukator_t.

    Цитата Сообщение от pal Посмотреть сообщение
    зачем же складывать. представьте, что у вас есть 10 разных подсистем, в каждой из которых будет void *.
    что помешает вызвать функцию подсистемы а с указателем от подсистемы б ?
    нету void*. человек делает вызов trasglukator_t t=transglukator_init(); Зачем его передавать потом в bukazoid_destroy ?
    что мешает программисту взять кубический корень из windows handle? Очевидно здравый смысл.

    Цитата Сообщение от pal Посмотреть сообщение
    как я уже говорил, это будет дырой в системе типов. это все равно, что предложить warning на любое недозволенное преобразование. какой в этом смысл, если в том месте, в котором это действительно нужно ( а есть ли такое ? ), можно прописать явное приведение, которое будет бросаться в глаза.
    стандартный вариант компиляции - ошибка. компиляция с взведенным флагом - ворнинг. компиляция с флагом совместимости - без сообщений. Все, больше ничего не надо и время нас рассудило бы. Может через 20 лет лишние флаги бы умерли за ненадобностью.
    У меня CXXFLAGS установлены в одно, у кого-то - в другое значение. Все довольны.
    Расскажите, почему этого нельзя было сделать. Почему я могу компилировать K&R программы многолетней давности на С и немогу это делать на С++. Нарушение обратной совместимости - имхо признак дикой неряшливости дизайна.
    И надо очень сильно молиться на систему типов, чтобы поставить ее выше в своей системе ценностей.

    Цитата Сообщение от pal Посмотреть сообщение
    да и с не дает, т.к. он не первый язык высокого уровня
    Ознакомьтесь с историей и целями создания С и UNIX. С - первый язык высокого уровня, который позволил эффективно писать низкоуровневые блоки. До С все ядра ОС писались на ассемблере и портируемость ОС ограничивалась двумя-тремя архитектурами. Вместе С была создана первая коммерческая ОС полностью написанная на машинно-независимом языке. Эта ОС (UNIX) живет до сих пор.
    Ничего близкого С++ не создавал и не создаст. Нет задач, которые может решить только С++. Были задачи которые смог решить только С. Они есть и сейчас, никто не мешает написать свой драйвер ядра на С++. Но почему-то желающих нет. А если находятся, то не находятся желающие этим драйвером пользоваться.

    Цитата Сообщение от pal Посмотреть сообщение
    никто и не спорит. однако на с++ их решать удобнее
    Удобство - критерий субъективный. Мне неудобнее. Программисту, которому на выбор надо выучить с нуля С и написать на нем проект, либо программисту который должен с нуля выучить С++ + ООП + все аббревиатуры + все шаблоны + как правильно писать (это ведь нетривиальная задача неудобнее. Програмисту, который матюкаясь читает код, переполненный перегруженными функциями и операторами и 10 (! сам видел) уровнями наследования - неудобнее, но это он матюкается пока не сел за отладчик, вот тут он поймет, что такое неудобно. Руководству eBay в проектах которого количество членов класса превышало возможности компилятора - неудобно.
    Давайте лучше к объективным критериям вернемся.


    Цитата Сообщение от pal Посмотреть сообщение
    проблема в том, что ни компилятор, ни линкер не смогут проследить за тем, что эта библиотека не обменивается указателями с окружающим миром. как раз с "библиотекой для отладки" я и сталкивался
    Есть ли жизнь за пределами компилятора? Или лучше так - если компилятор чего-то не может, то этого не может никто
    Если для вас даже задачи статического чекинга должны выполняться компилятором, то я даже не знаю что сказать.
    Есь очень много программ, работающих с кодом напрямую без компилятора. На С++ их меньше, так как у С++ усложненный синтаксис. Что убъет язык в тот момент, когда на рынок придут функциональные языки индустриального класса.
    Что характерно, С выживет.
    Кстати, вы с openC++ не работали?

    Цитата Сообщение от pal Посмотреть сообщение
    pthread_once_t это просто инт в виде флагов
    pthread_spinlock_t это тоже флаг
    если я контролирую thread pool, то мне может понадобиться массив pthread_once_t. И в этом случае он действительно удобней как int и инициализация будет в цикле.
    А вот массив cond_t либо condattr_t никому не нужен, обычно это один объект, на который ссылаются другие.
    Хотя конечно, при работе с pthread эффективность всегда на первом месте, удобство пользования все-таки есть, но это не удобство в понимании объектников (пусть придет мама (необъектная) и сделает мне хороший компилятор, который все сделает за меня), это аскетическая простота использования и минимализм.
    pthread не относится напрямую к glibc, я его просто с потолка выбрал, по причине простоты. А вообще glibc - относительно старая библиотека с феноменальной портируемостью и очень неплохой эффективностью. Т.е. в моих терминах показатели функциональности и эффективности на высоте, удобства - в приемлимых рамках.
    Я не думаю, что boost при своей идеологии в состоянии повторить эту аскетичность и простоту.
    The future is already here - it is just unevenly distributed. (c) W. Gibson


Ответить в теме
Страница 1 из 8 1 2 3 ... ПоследняяПоследняя

Социальные закладки

Социальные закладки

Ваши права

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