прошу модераторов перенести сюда ветку из топика C++ vs Java начиная с поста 88
|
прошу модераторов перенести сюда ветку из топика C++ vs Java начиная с поста 88
The future is already here - it is just unevenly distributed. (c) W. Gibson
Мдя никогда не думал что будут сравнивать С и С++
На С все равно ничего большого не напишешь.
2 homo ludens и чем же С лучше чем С++ ?
практический любой правильный С-интерфейс. Правильные С-интерфейсы можно легко найти в glibc и сопутствующих продуктах. Возьмите например POSIX threads (pthread_t).Сообщение от pal
давайте напишем интерфейс на С объекта 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* должен явно преобразовываться к типу. Одним этим выстрелом они убили много зайцев - один из которых - уничтожение обратной совместимости с С. Неслабо, да?
Возможна конечно, хотя с частичной потерей эффективности. Почему нет? Просто абстракции должны иметь поменьше дырок. Более того, потеря функциональности тоже возможна, но функциональность не должна подменяться удобством. Это абсолютно разные вещи. try/catch не расширяет функциональность, также как и uBlas. Иначе мы получаем то что имеем - из случайно выбранных 10 проектов на sf.net 9 будут просто оболочками-адаптерами к чужому коду, оболочками с нулевой функциональностью, но удобным (не для всех) интерфейсом. Удобство - категория субъективная, а функциональность - нет. Вот и весь критерий.Сообщение от pal
продолжаем? я еще не на все вопросы ответил...
The future is already here - it is just unevenly distributed. (c) W. Gibson
я нигде в своем посте не писал о макросах.
я писал о разделении уровней и понижении связности кода. Макросы в этом примере не используются нигде.
То, что проектировать интерфейс надо правильно - банальность. Но на С++ почему-то редко так делают. Ваш вариант проектирования - это трюк 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
"Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки,"
а механизм абстрактных классов и виртуальные функции это встроенные средства языка
про правильное проектирование на с++ - это делают гораздо чаще чем на с
думаю дизайн документов для с++ проектов гораздо больше чем для С
тут вообще другой момент - говоря про проектирование, Вы все время уходите в компилирование и линкование
это вообще разные вещи. жизнь проекта с неправильным дизайном и отточенной компиляцией\линкованием гораздо меньше чем проекта с правильным дизайном
мы ведь не будем ставить в упрек с++ плохость вашей реализации на нем ?
вы его не используете по другой причине: вы не знаете, что он определен в <cmath>, а не в <algorithm>(это к тому, почему я никогда не пользую std::abs - посмотрите сколько мусора он за собой тянет).
если речь об идиоме pimpl, то ее используют с несколько более широкими целями. можно реализовать value semantics, что вообще невозможно на с, на худой конец, можно удостовериться что обьект будет правильно разрушен.1. написать псевдоадаптер - пустой класс-оболочку только с вызовами другого класса. без динамических переменных это обычно сложно. Кроме того лапша этих псевдоадаптеров намного хуже вермишели макросов, макрос - это одна-две строчки, а псевдоадаптер - это файл. Читаемость кода при этом тоже не повышается. Зато повышается его связность.
у вас же в случае void * его можно удалить free с потерей всех остальных ресурсов, либо в случае int можно делать очень много других ненужных операций, а в конце все равно не удалить
при желании на с++ можно делать точно так же, как и на с:
class A; A * f ( ); void g ( A * ); ...
в качестве дополнительного бонуса вы не передадите его функции, которая ждет тоже void * или int, но на самом деле совсем другой, также delete на неопределенный класс будет ругаться ( помните, я говорил не использовать malloc/free ? ). только так делать не надо, потому что кто-то обязательно забудет его удалить.
еще можно использовать абстрактный базовый класс и возвращать smartpointer на конкретную реализацию, если вам не жалко виртуальных функций.
как мы видим, на с++ можно сделать точно так же, только лучше, а можно слегка по другому, но еще лучше
я знаю, что он написан на с++. где вы такое видели ?Кстати для темплейтов эта практика просто необходима, нормально реализованный шаблон - это только интерфейсы к единой для всех его реализаций библиотеке.
Как вы думаете, почему stl написан на С?
вы, похоже, шаблоны с чем-то другим перепутали
как я уже показал, так делать нельзя и не надо никогда2. напрямую использовать С-шные методы описанные выше.
учитывая, что к void * преобразовывается автоматом, разрешение обратного преобразования одним махом сводит на нет всю систему типов - любой тип автоматически превращается в любой другой через void *.метод с хендлом типа int (юзается когда надо поддерживать целостность коллекции трансглюкаторов) работает. А вот с void* иногда бывают проблемы.
Почему? А потому что умники из комитетов по религиозно-объектной чистоте постановили - void* должен явно преобразовываться к типу. Одним этим выстрелом они убили много зайцев - один из которых - уничтожение обратной совместимости с С. Неслабо, да?
может, вам просто ближе к сердцу языки с динамической типизацией и рантайм проверками ? это не стыкуется с вашей обеспокоенностью эффективностью исполнения.
так же нет никакой проблемы в этой несовместимости с с. разве, что вы захотите перевести программу с с на с++. тогда надо радоваться, заодно несколько ошибок вокруг void* обнаружите
с этим трудно не согласиться, но как вы из этого сделали вывод, что абстракций быть не должно ?Возможна конечно, хотя с частичной потерей эффективности. Почему нет? Просто абстракции должны иметь поменьше дырок.
я не могу разобраться в вашей терминологии. чем отличается функциональность от удобства, если преимуществом с по сравнению с ассемблером является функциональность, а преимуществом с++ по сравнению с с - удобство ? или у вас есть с, который каким-то сверхъестественным образом выполняется процессором телепатически с большей функциональностью, чем ассемблер ?Более того, потеря функциональности тоже возможна, но функциональность не должна подменяться удобством. Это абсолютно разные вещи. try/catch не расширяет функциональность, также как и uBlas. Иначе мы получаем то что имеем - из случайно выбранных 10 проектов на sf.net 9 будут просто оболочками-адаптерами к чужому коду, оболочками с нулевой функциональностью, но удобным (не для всех) интерфейсом. Удобство - категория субъективная, а функциональность - нет. Вот и весь критерий.
попробуйте на досуге найти в /usr/include/c++/4.1.*/tr1/ реализацию std::tr1::bind. а там даже goto в макросах нет
но это все мелочи по сравнению с тем, что бывает когда кто-то переопределяет malloc/free/realloc, и при этом обменивается указателями с модулями, где ничего такого не переопределено.
я боюсь, что вы выбрали не совсем правильный интерфейс
на весь 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;
Я ведь сразу сказал, что это худший вариант.
Однако куча программеров так пишет. Более того для многих junior'ов это нормальный код. :- (
потому что с <cmath> у меня это вообще не компилится. Бедный компилятор не может выбрать какую из перегруженных функций ему выполнять - float, double или long double.
Удалять его free никому в голову не придет. А насчет забыть - так для динамически определяемой памяти это верно и для С++. Не юзать динамическую память без обверток?
Вы с windows handle тоже делаете много ненужных вещей?
Идея в том, что обычно transglukator_t появляется только в вызовах функций собственного интерфейса. Или в промежуточных переменных. Никому в голову не придет допустим складывать объекты этого типа. Кроме программиста С++ привычного к перегрузкам операторов. : -)
На С++ это можно сделать сложнее и единственный плюс, который я здесь вижу - контроль типов, который таки да полезен, когда мы его действительно хотим видеть. И вреден, когда мы его не хотим видеть.
Кроме того, кто-то из известных программистов сказал очень умную вещь - хороший язык, это тот, в котором правильную вещь можно сделать единственным способом.
А я добавлю от себя - правильная реализация в хорошем языке должна отличаться от неправильных тем, что имеет самый компактный и элегантный интерфейс, тем самым создавая общую эстетику для групп программистов и облегчая взаимное понимание кода.
В С++ эти правила не выполняются.
Есть правда пару нюансов с наследованием, но имхо в правильной программе наследование должно юзаться реже чем longjump.
Изначально библиотека писалась на С. Потом была переделана на С++, но внутри это выглядело как C+generic programmig, разобраться там было достаточно сложно, код сверхсвязный. Впрочем внутри я рассматривал раниие реализации от HP и достаточно давно. Однако в википедии написано вот что.
Я тоже не представляю себе эффективной реализации контейнеров по другому как в виде объектных интерфейсов к void* контейнерам. Возможно вы меня просветите.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* можно было сделать warning'ом. Тогда бы этих проблем не было бы и все были бы довольны.
они не должны быть дырявыми либо если уж они дырявы, должна быть возможность эти дырки заткнуть. Абстракция должна давать больше чем забирать. Пример - интерфейсы файловых дескрипторов (open/close/read/write). Этот интерфейс очень абстрактен, потому дыряв. Работая с устройством или с сокетом или с файлом на диске вы работаете в общей абстракции. Но когда ее не хватает - есть ioctl
С более функционален, чем ассемблер. В момент появления С все операционки писались на ассемблере конкретной машины. После его появления стало возможным писать их для любой машины. Это - пример расширения функциональности. С++ такого расширения не дает. Нет прикладных задач, которые можно решить на С++ но нельзя решить на С.
Концепция функциональности против удобства на самом деле достаточно сложна для понимания и потребует не менее страницы постов. Могу написать в свободное время.
это действительно маразм, причем фатальный. Однако в реальной жизни переопределения обычно делают либо для локальной библиотеки в период отладки, либо глобально для всего проекта (mtrace), опять таки на период отладки.
они не могут являться интами!!!
Это дескрипторы в таблице, другой вопрос, что таблица может храниться в ядре ОС, а может обрабатываться в библиотеке. В любом случае pthread_t - это куча указателей и дескрипторов. Если файловый дескриптор POSIX интерфейса (на котором весь инет держится) - int, это же не значит, что он реально целый. Это индекс в таблице значительно более сложной, чем то, что мы видим. Нету меня здесь сырцов glibc под рукой, они ж огромные, их тянуть задолбаешься. Одни h-файлы.
Кажется мне пора приводить примеры практических вещей, которые можно сделать на С и нельзя на С++
: -)
The future is already here - it is just unevenly distributed. (c) W. Gibson
Кстати эти структуры в pthread.h там тоже не зря определены. Дело в том, именно их иногда нужно инициализировать статически. А вот pthread_t статически инициализировать никому в голову не придет. Поэтому он - int.
The future is already here - it is just unevenly distributed. (c) W. Gibson
вы действительно считаете, что pthread_once_t можно инициализировать как-то иначе, чем статически ?
более того, не все из определенных структур имеют макросы для инициализации. т.е. вы не правы в обе стороны. только pthread_t на самом деле является указателем на структуру, потому что ее выделять нельзя что статически, что динамически.
Тогда дискутируйте с монстрами ООП - это они рекомендуют вместо наследования использовать композицию везде где это можно. Есть даже такое выражение - anti-pattern yo-yo. Кажется даже в GoF это было, хотя могу ошибаться, текстов под рукой нет.
Инициализируются статически как раз те структуры, которые представлены не хендлами.
Я могу написать pthread_cond_t x=PTHREAD_COND_INITIALIZER
там как раз все макросы описаны такого типа.
на первый взгляд как бы изящней их енумераторами сделать, но если человеку надо будет работать с членами структуры, то этот метод - комбинирует все достоинства и самый простой.
чтобы было чем заткнуть дырки в абстракциях.
The future is already here - it is just unevenly distributed. (c) W. Gibson
замените компилятор
почему не придет ? void* так и напрашивется на freeУдалять его free никому в голову не придет.
это только в максимально приближенном варианте. в случае с pimpl или с умными указателями все само удалится.А насчет забыть - так для динамически определяемой памяти это верно и для С++.
совершенно верно ( максимально, на сколько это возможно )Не юзать динамическую память без обверток?
не пользуюсь. но любой инт можно случайно передать вместо другого инта, скажем, в функцию, получающую несколько интов. и компилятор это проглотит, не поперхнувшись. в случае же указателя на уникальный класс, будет ошибка.Вы с windows handle тоже делаете много ненужных вещей?
зачем же складывать. представьте, что у вас есть 10 разных подсистем, в каждой из которых будет void *.Идея в том, что обычно transglukator_t появляется только в вызовах функций собственного интерфейса. Или в промежуточных переменных. Никому в голову не придет допустим складывать объекты этого типа. Кроме программиста С++ привычного к перегрузкам операторов. : -)
что помешает вызвать функцию подсистемы а с указателем от подсистемы б ?
не хотите - в с++ есть reinterpret_cast. однако, он не произойдет вдруг, сам собой, когда его никто не ждал.На С++ это можно сделать сложнее и единственный плюс, который я здесь вижу - контроль типов, который таки да полезен, когда мы его действительно хотим видеть. И вреден, когда мы его не хотим видеть.
контроль типов не просто полезен, я вообще не представляю, как без него писать программы, сложнее helloworld
ну вот, с нашими типами, правильные реализации элегантны, а reinterpret_cast - нет. у вас есть какой-то контр-пример ?Кроме того, кто-то из известных программистов сказал очень умную вещь - хороший язык, это тот, в котором правильную вещь можно сделать единственным способом.
А я добавлю от себя - правильная реализация в хорошем языке должна отличаться от неправильных тем, что имеет самый компактный и элегантный интерфейс, тем самым создавая общую эстетику для групп программистов и облегчая взаимное понимание кода.
В С++ эти правила не выполняются.
наследование, конечно, надо применять к месту, а вот longjmp в хороших программах вообще не используют.Есть правда пару нюансов с наследованием, но имхо в правильной программе наследование должно юзаться реже чем longjump.
может все-таки, это был с++, просто это было давно и с++ тогда был немного другой ? ну и вы должны понимать, что инлайн без связности не получитсяИзначально библиотека писалась на С. Потом была переделана на С++, но внутри это выглядело как C+generic programmig, разобраться там было достаточно сложно, код сверхсвязный.
ну, с тех пор не только реализации, но и спецификации сильно поменялисьВпрочем внутри я рассматривал раниие реализации от HP и достаточно давно.
это касается только контейнеров указателей и эффективности в терминах объема сгенерированного кода, когда вы используете много однотипных контейнеров разных типов указателей.Я тоже не представляю себе эффективной реализации контейнеров по другому как в виде объектных интерфейсов к void* контейнерам. Возможно вы меня просветите.
это всего лишь частный случай ситуации, когда шаблон имеет много операций, не зависящих от его параметров, тогда их выделяют в нешаблонный предок, чтобы не генерить один и тот же код для шаблонов с разными параметрами.
и не должна. достаточно иметь возможность подключать с заголовки. при особом желании в следующем стандарте с могут озаботиться о совместимости и о программистах, как уже сделали местами в с99С-программа не компилируется в общем случае на С++.
как я уже говорил, это будет дырой в системе типов. это все равно, что предложить warning на любое недозволенное преобразование. какой в этом смысл, если в том месте, в котором это действительно нужно ( а есть ли такое ? ), можно прописать явное приведение, которое будет бросаться в глаза.Предупреждение о конверсии void* можно было сделать warning'ом. Тогда бы этих проблем не было бы и все были бы довольны.
интерфейс дескрипторов плох, ioctl еще хуже, но я в них вижу демонстрацию недостатков с по сравнению с с++они не должны быть дырявыми либо если уж они дырявы, должна быть возможность эти дырки заткнуть. Абстракция должна давать больше чем забирать. Пример - интерфейсы файловых дескрипторов (open/close/read/write). Этот интерфейс очень абстрактен, потому дыряв. Работая с устройством или с сокетом или с файлом на диске вы работаете в общей абстракции. Но когда ее не хватает - есть ioctl
да и с не дает, т.к. он не первый язык высокого уровняС более функционален, чем ассемблер. В момент появления С все операционки писались на ассемблере конкретной машины. После его появления стало возможным писать их для любой машины. Это - пример расширения функциональности. С++ такого расширения не дает.
никто и не спорит. однако на с++ их решать удобнееНет прикладных задач, которые можно решить на С++ но нельзя решить на С.
проблема в том, что ни компилятор, ни линкер не смогут проследить за тем, что эта библиотека не обменивается указателями с окружающим миром. как раз с "библиотекой для отладки" я и сталкивалсяэто действительно маразм, причем фатальный. Однако в реальной жизни переопределения обычно делают либо для локальной библиотеки в период отладки, либо глобально для всего проекта (mtrace), опять таки на период отладки.
pthread_t это действительно указатель на структуру, маскирующийся интомони не могут являться интами!!!
Это дескрипторы в таблице, другой вопрос, что таблица может храниться в ядре ОС, а может обрабатываться в библиотеке. В любом случае pthread_t - это куча указателей и дескрипторов.
pthread_key_t это инт, являющийся индексом массива
pthread_once_t это просто инт в виде флагов
pthread_spinlock_t это тоже флаг
дескиптор это индекс, но не от хорошей жизни, а в целях безопасности. причем, он совсем не защищает программу от ее ошибки, только другие программы от злонамеренной программы.Если файловый дескриптор POSIX интерфейса (на котором весь инет держится) - int, это же не значит, что он реально целый. Это индекс в таблице значительно более сложной, чем то, что мы видим. Нету меня здесь сырцов glibc под рукой, они ж огромные, их тянуть задолбаешься. Одни h-файлы.
поддерживаюКажется мне пора приводить примеры практических вещей, которые можно сделать на С и нельзя на С++
: -)
у меня есть теория
pthread_t - единственный скрытый указатель, потому что эту структуру клиентский код самостоятельно ( без хелперов ) размещать не имеет никакой возможности. все остальные можно размещать в стеке/статически, т.е. моментально, следовательно, при дизайне озаботились в первую очередь о скорости
не думаю что мне придется с ними диспутировать по поводу частоты употребления наследования по сравнению с лонгджампами
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
на двух тачках с разными архитектурами.
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)
какой void*? человек видит transglukator_t.
нету void*. человек делает вызов trasglukator_t t=transglukator_init(); Зачем его передавать потом в bukazoid_destroy ?
что мешает программисту взять кубический корень из windows handle? Очевидно здравый смысл.
стандартный вариант компиляции - ошибка. компиляция с взведенным флагом - ворнинг. компиляция с флагом совместимости - без сообщений. Все, больше ничего не надо и время нас рассудило бы. Может через 20 лет лишние флаги бы умерли за ненадобностью.
У меня CXXFLAGS установлены в одно, у кого-то - в другое значение. Все довольны.
Расскажите, почему этого нельзя было сделать. Почему я могу компилировать K&R программы многолетней давности на С и немогу это делать на С++. Нарушение обратной совместимости - имхо признак дикой неряшливости дизайна.
И надо очень сильно молиться на систему типов, чтобы поставить ее выше в своей системе ценностей.
Ознакомьтесь с историей и целями создания С и UNIX. С - первый язык высокого уровня, который позволил эффективно писать низкоуровневые блоки. До С все ядра ОС писались на ассемблере и портируемость ОС ограничивалась двумя-тремя архитектурами. Вместе С была создана первая коммерческая ОС полностью написанная на машинно-независимом языке. Эта ОС (UNIX) живет до сих пор.
Ничего близкого С++ не создавал и не создаст. Нет задач, которые может решить только С++. Были задачи которые смог решить только С. Они есть и сейчас, никто не мешает написать свой драйвер ядра на С++. Но почему-то желающих нет. А если находятся, то не находятся желающие этим драйвером пользоваться.
Удобство - критерий субъективный. Мне неудобнее. Программисту, которому на выбор надо выучить с нуля С и написать на нем проект, либо программисту который должен с нуля выучить С++ + ООП + все аббревиатуры + все шаблоны + как правильно писать (это ведь нетривиальная задача неудобнее. Програмисту, который матюкаясь читает код, переполненный перегруженными функциями и операторами и 10 (! сам видел) уровнями наследования - неудобнее, но это он матюкается пока не сел за отладчик, вот тут он поймет, что такое неудобно. Руководству eBay в проектах которого количество членов класса превышало возможности компилятора - неудобно.
Давайте лучше к объективным критериям вернемся.
Есть ли жизнь за пределами компилятора? Или лучше так - если компилятор чего-то не может, то этого не может никто
Если для вас даже задачи статического чекинга должны выполняться компилятором, то я даже не знаю что сказать.
Есь очень много программ, работающих с кодом напрямую без компилятора. На С++ их меньше, так как у С++ усложненный синтаксис. Что убъет язык в тот момент, когда на рынок придут функциональные языки индустриального класса.
Что характерно, С выживет.
Кстати, вы с openC++ не работали?
если я контролирую 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
Социальные закладки