LINUX.ORG.RU

Может кто нибудь показать красоту с++?

 ,


7

9

Может кто нибудь написать на c++, чтобы показать почему c++ лучше смотрится чем программа на си? Хотелось бы увидеть изящный код на c++, так, как это делают с хорошим опытом. Программу любую, главное чтобы было понятно, что c++ намного красивее в написании, чем си.

Ответ на: комментарий от XMs

То, что на кьютах реализуется всего в несколько строчек, на сях займёт от сотен до нескольких тысяч строк чистого кода (разумеется, беру только QtCore).

почему только QtCore ?
Виджеты тоже красивее сделаны чем gtk?
довелось мне тут cheese поправить - сишный ужас, как хорошо что я его не использую

x905 ★★★★★
()
Ответ на: комментарий от x905

почему только QtCore ?

Потому что графика, мультимедиа и прочие базы данных в любом случае реализуются через сторонние либы, поэтому вопрос будет в удобстве интерфейсов этих либ. QtNetwork не стал включать, потому что ему так же нет аналогов в STL, и программисту в любом случае пришлось бы писать кучу кода. А так — контейнеры есть и там, и там, строки, вот это всё. Т. е. это как бы сравнение Си с нормальным (в плане интерфейса) STL.


Виджеты тоже красивее сделаны чем gtk?

Если судить по QTreeView и его GTK-аналогу — да. НАМНОГО. Сравни:

XMs ★★★★★
()
Ответ на: комментарий от eao197

Неужели совсем нет никакого мнения по этому поводу? Или ты их тех, кто считает что так все и должно быть, а виноваты те кто не осилил?

У меня есть еще пара примеров если тебе этот не понравился.

pftBest ★★★★
()
Ответ на: комментарий от next_time

В отношениях child->parent граф порождения объектов сложнее дерева существовать не может (см. RAII).

А, ну граф порождения - это наше всё.

tailgunner ★★★★★
()
Ответ на: комментарий от tailgunner

А что не так с этим примером?

Программистам с других языков может быть неочевидно, что неявное преобразование const char* в bool имеет более высокий приоритет, чем const char* в std::string.

А вообще неявное преобразование зло, если бы были использованы правильные типы, ошибок бы не возникло...

fsb4000 ★★★★★
()
Ответ на: комментарий от pftBest

Неужели совсем нет никакого мнения по этому поводу?

Есть и не одно. Например, есть мнение, что нецензурное слово из трех букв можно выразить на любом языке, хоть русском, хоть английском, хоть финском. И что из этого?

Или ты их тех, кто считает что так все и должно быть, а виноваты те кто не осилил?

Скорее из тех, кто просто считается с объективной реальностью. Ну вот здесь так.

Хитрых примеров можно привести бесчисленное множество. Скажем:

#include <iostream>

namespace demo {

	struct data {
		int i_;
	};

	void print(const data &) { std::cout << "Die!" << std::endl; }
}

template<typename T>
void print(const T &) { std::cout << "Live!" << std::endl; }

template<typename T>
void live_or_die() {
	print(T{0});
}

int main() {
	live_or_die<int>();
	live_or_die<demo::data>();

	return 0;
}

Когда берешь инструмент, нужно понимать, что в нем есть и опасные моменты. И неоднозначные. И совершенно незнакомые.

Но в контексте спора «C vs C++» уж лучше иметь мощный инструмент, чем примитивный. Пусть за это даже и приходится платить дороже. Это все равно окупается.

eao197 ★★★★★
()
Ответ на: комментарий от fsb4000

Программистам с других языков может быть неочевидно

Я даже больше скажу. Многим C++программистам неочевидно, что «Hello!» — это const char[7].

eao197 ★★★★★
()
Ответ на: комментарий от XMs

Если судить по QTreeView и его GTK-аналогу — да. НАМНОГО. Сравни:

согласен, моя предыдущая фраза должна была звучать так :

Виджеты [на qt] тоже красивее сделаны чем gtk ! 


)

x905 ★★★★★
()
Ответ на: комментарий от Virtuos86

И вы это выясняли 8 страниц?

Не, тут объясняли C-шниками убогость чистого C. Даже в сравнении с некрасивым C++ :)

eao197 ★★★★★
()
Ответ на: комментарий от driver

STL, корни которой уходят в метапрограммирование. В Си такого нет.

Я вот давненько искал STL для безплюсых и таки нашел. Пришлось только вытаскивать проджект с загибающегося code.google.com. Так что теперь он под моим крылом https://github.com/Hikawa/ccl Правда я его не трогаю ни в смысле правок, ни узания. Тем не менее препроцессор - костыль не сильно хуже, чем шаблоны и позволяет спокойно обходится без последних.

q0tw4 ★★★★
()
Ответ на: комментарий от q0tw4

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

И тут естественным образом возникает вопрос о том, а насколько макросы «раздувают» код? И сказываются на производительности оного.

eao197 ★★★★★
()
Ответ на: комментарий от tailgunner

Впрочем, как скажешь.

Хорошо. Будем считать, что по этому пункту договорились.

Люблю эту цитату.

Да, я уже понял, что ты любишь подменять аргументы бессмыслицей.

Я напомню нить разговора:

Разговора? Был (риторический) вопрос: Может кто нибудь показать красоту с++? (комментарий).

Ссылка ведёт не на твой риторический вопрос, а на мой риторический ответ. А после них было ещё несколько постов.

Твой вклад в этот разговор - объяснение, что такое стиль

И это тоже, раз ты не понимал значения этого слова.

и фантазии об аллокаторах и фиксированных адресах

И снова голословное утверждение. Почему фантазии?

Ну а после этого Может кто нибудь показать красоту с++? (комментарий) очевидно, что ты некомпетентен примерно полностью.

И опять, почему?

На данный момент мы имеем 3 твоих абсолютно голословных утверждения:

  1. То, что массивы char могут быть статическими или на стеке, а string нормально (без создания сотни аллокаторов) статическими не сделать — чушь.
  2. Аллокаторы и фиксированные адреса — это фантазии.
  3. Я абсолютно некомпетентен.

Ни одно из утверждений не было аргументировано. От ответа на вопрос, касающийся 1-ого утверждения, ты ушёл, процитировав Гибсона, не имеющего отношения к разговору, и произнёс ещё несколько бессмысленных в контексте разговора фраз, а также сделал 2 новых голословных утверждения. Наверно, это и есть признак абсолютной компетентности.

aureliano15 ★★
()
Ответ на: комментарий от q0tw4

Правда я его не трогаю ни в смысле правок, ни узания

Я правильно понимаю - ты это чудо не правишь и не используешь?

tailgunner ★★★★★
()
Ответ на: комментарий от next_time

переполнение signed int - максимальное значение знаковой i меньше максимального значения беззнакового size, соотв. в ситуации когда size достаточно велик, будет UB

Понял. Читал вашу с azelipupenko дискуссию по этому поводу. Согласен с тем, что в общем случае лучше делать переменную i типа size_t или как минимум unsigned. Однако из того, что она signed int, ещё не следует, что это всегда ub. Даже если size имеет тип unsigned и размер, больший или равный i. Например, когда реальный размер всегда ограничен некоторым не очень большим числом. Тут можно говорить о потенциальной опасности, связанной с ub или отрицательным индексом, когда размер надо будет увеличить, а про i все забудут за давностью лет. Но пока максимально возможный размер не велик, это не ub.

aureliano15 ★★
()
Ответ на: комментарий от tailgunner

Правда я его не трогаю ни в смысле правок, ни узания

Я правильно понимаю - ты это чудо не правишь и не используешь?

Он созерцает. «Сидел я молча у окна и наслаждался тишиной. Моя любовь всегда была со мной…»

Virtuos86 ★★★★★
()
Ответ на: комментарий от aureliano15

Да, я уже понял, что ты любишь подменять аргументы бессмыслицей.

Ты милостиво дозволил мне цитировать того, кого я захочу. Чем ты недоволен - ХЗ.

и фантазии об аллокаторах и фиксированных адресах

И снова голословное утверждение. Почему фантазии?

Потому что аллокаторы и фиксированные адреса относятся к тому, о чем _я_ говорил, ровно никак.

tailgunner ★★★★★
()
Ответ на: комментарий от annulen

строки и другие классы Qt по скорости уступают аналогичным из STL

Два момента:

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

aureliano15 ★★
()
Ответ на: комментарий от annulen

Мне трудно себе представить надёжное не глючное ядро на шаблонах, как и производительное ядро, использующее виртуальные функции и длинные цепочки наследования с конструктором на каждом шаге.

Придется развить воображение. Для примера, в Linux повсеместно применяются контейнеры, «виртуальные» функции и наследование. А goto вместо деструкторов это высший пилотаж.

Если речь об указателях на функции и вложенных структурах, то это не совсем то. При использовании любого числа вложенных си-структур, для каждой из них при создании не выполняется код. Аналогично, указатели на функции могут использоваться там, где это нужно программисту, а виртуальные функции — всегда виртуальные. Нет, я знаю, что и виртуальную функцию можно вызвать как обычную, но обычно никто так не делает, т. к. в этом случае исчезает смысл использования виртуальных функций. Т. е. сама концепция ООП направлена на создание более безопасного и легко сопровождаемого, но менее эффективного кода. Что касается шаблонов, то использование абстрактных типов в коде ядра, которые могут порождать или не порождать конкретные функции (причём в одной версии функция может быть порождена, а в следующей уже исчезнуть) может привести к серьёзным проблемам, которые сведут на нет весь профит. Даже если шаблонами пользоваться аккуратно.

aureliano15 ★★
()
Последнее исправление: aureliano15 (всего исправлений: 1)
Ответ на: комментарий от tailgunner

Да, я уже понял, что ты любишь подменять аргументы бессмыслицей.

Ты милостиво дозволил мне цитировать того, кого я захочу. Чем ты недоволен - ХЗ.

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

и фантазии об аллокаторах и фиксированных адресах

И снова голословное утверждение. Почему фантазии?

Потому что аллокаторы и фиксированные адреса относятся к тому, о чем _я_ говорил, ровно никак.

Так откуда ж я могу знать, о чём ты говорил, если ты молчишь об этом?

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

Так откуда ж я могу знать, о чём ты говорил

И в самом деле - откуда тебе знать, на что ты отвечал.

tailgunner ★★★★★
()

На примере std::map.

Шаблоны и оопшность позволяют лаконично и универсально реализовать следующие:

1) Мы можем написать свой аллакатор. Например если мы знаем макс кол-во элементов в мапе, то мы можем написать аллокатор на статическом буфере. Это может позволить нам исбежать вызовов к ос, выделения памяти на хипе. Что сделать аллокация а) быстрее; б) более предсказуемую по продолжительности. Аллокация будет занимать константное время. А можно не париться и использовать стандартный аллокатор. Для этого(случая когда тебе надо алоцироваться не на хипе) тебе надо написать только аллокатор, без миллионов строк кода.

2) В мапе есть операция сравнения с помощью которой и происходит поиск элементов в ней. В общем случае это операция <. Но ты можешь определить свою операцию например для изменения порядка сортировки, или для особого сравнения(например с игноирированием регистра), или есл операции сравнения нет в принципе для типа ключа. И сделать ты это можешь тоже очень лаконично и просто.

3) Ты можешь описать любую мапу просто как std::map<Tkey, TVal> mp; не запариваясь вообще о доп коде для новых типов (с некоторыми оговорками, но которые не актуальны в большинстве случаев)

4) Ты можешь создать мапу(как в прочем и вектор, и список, и сет, и std::array) из двух итераторов на рендж того же типа. А итератором является в том числе и указатели на элементы обычного массива

Ниже пример правда для сета:

  char buf[255];
  FillBuf(buf, 255);
  std::set<char> st(buf, buf+255);

5) Доп пример, при помощи шаблонов ты можешь писать обертки например для случаев когда тебе надо использовать выравненые данные

Вместо

  void f(int* ptr, size_t data) {....} //PLEASE USE ALIGINED DATA(by 32bytes)

Это

  template<class T, size_t SZ>
  struct ABuf {
    T buf[SZ] __attribute__ ((aligned (32)));
  };
  void f_impl(int* buf, size_t sz) {....}

  template<size_t SZ>
  inline void f(ABuf<int, SZ>& buf) {f_impl(buf.buf, SZ);}
  

Само описание выглядит более запутаным, зато оно более устойчиво к ошибкам передачи не тех данных в такую функцию. Требование выравнивание задано API, а не коментом в хэдере или доп требованием в доке. Если API явно требует формат - это всегда лучше, чем описание требования в доке. И этот вариант имеет нулевое отличие по скорости исполнения (да и по объему памяти, и по кол-ву генерируемого кода) от первого варианта. Зато он предоставляет больше гарантий и меньше пространства для ошибок.

Продолжать можно долго. Эти приемущества в основном связаны с шаблонами. Приемущества ООП(использование интерфейсов, абстракций полимофризма) я описывать не буду - об этом и так сотни книг и статей написано.

Dudraug ★★★★★
()
Последнее исправление: Dudraug (всего исправлений: 1)
Ответ на: комментарий от eao197

насколько макросы «раздувают» код?

Так же как и шаблоны. Спасение - умные компиляторы типа ghc, умеющие подобрать определенный набор типов для инстанцирования, а остальное пустить через полиморфизм. Ну или jit компиляторы, генерящие на лету только то, что реально используется (эмм, а это реально лучше раздувания выходит?). Ну еще руками можно так сделать, в смысле отдельно int, отдельно float и class Object для прочего, лишь бы dynamic_cast оптимизированный был.

q0tw4 ★★★★
()
Ответ на: комментарий от q0tw4

Так же как и шаблоны.

Так шаблоны-то код не раздувают.

И, кстати говоря, в шаблонных классах код генерируется только для тех методов, которые вызываются. Например, если есть std::list<MyClass>, и в программе нигде не вызывается std::list<MyClass>::sort(), то код для std::list<MyClass>::sort() даже не инстанциируется.

eao197 ★★★★★
()
Ответ на: комментарий от q0tw4

насколько макросы «раздувают» код?

Так же как и шаблоны.

Я думаю, что так же, как inline-функции, независимо от того, шаблонные они или нет. С другой стороны, в отдельных случаях макросы и inline'ы могут этот код даже сократить. Например, вызов макроса или инлайн-функции abs(-1) нормальный компилятор заменит на 1, а вот вызов настоящей функции abs(-1) заменить на 1 не получится.

aureliano15 ★★
()
Ответ на: комментарий от eao197

И, кстати говоря, в шаблонных классах код генерируется только для тех методов, которые вызываются. Например, если есть std::list<MyClass>, и в программе нигде не вызывается std::list<MyClass>::sort(), то код для std::list<MyClass>::sort() даже не инстанциируется.

То же верно и для макросов с inline-функциями.

aureliano15 ★★
()
Ответ на: комментарий от q0tw4

Линкер же дропает не вызываемые функции в экзешке. Или я что-то не так понял?

Еще и до линкера дело не доходит. В моем MyClass может не быть operator<(), который нужен внутри std::list<MyClass>::sort(). И, если я не вызываю sort(), то это никаких проблем не вызывает, т.к. компилятор не инстанциирует этот метод.

eao197 ★★★★★
()
Ответ на: комментарий от aureliano15

То же верно и для макросов с inline-функциями.

Я думаю, вы просто не понимаете, о чем идет речь.

eao197 ★★★★★
()
Ответ на: комментарий от pftBest

Но ведь эта «красота» - это следствие стремления к обратной совместимости с обычным си. Я давно считал, что строки в си++(да и многое другое) во многом ущербны именно из-за того, что нужна эта совместимость.

Dudraug ★★★★★
()
Последнее исправление: Dudraug (всего исправлений: 1)
Ответ на: комментарий от fsb4000

Программистам с других языков может быть неочевидно

Но мы вроде сранивали с++ с чистым си, а не с другими языками, где совместимость с си не закладывалась изначально? Я думаю тем кто знает си и начал учить плюсы будет понятен корень проблемы здесь.

Dudraug ★★★★★
()
Ответ на: комментарий от q0tw4

Хм. А С умеет инлайн?

Современный си — умеет (начиная с c99). И как говорил царь (а я потом проверил, и это так и есть), никогда не заменяет инлайны на не инлайны, в отличие от крестов. Например, рекурсивная inline-функция (которых быть не должно) в c++ прекрасно компилится в обычную, а в си на этапе линковки выдаётся ошибка о вызове несуществующей функции.

aureliano15 ★★
()
Ответ на: комментарий от aureliano15

В C++ inline означает "разрешено более чем одно определение в программе", а не подсказку к оптимизатору как в C.

d_a ★★★★★
()
Ответ на: комментарий от q0tw4

Извиняюсь за непреднамеренный обман. Сейчас ещё раз проверил более внимательно, и выяснил, что царь наврал. Инлайн в си и в си++ ведут себя абсолютно одинаково и являются в обоих случаях рекомендацией, необязательной к исполнению. По крайней мере в gcc. А ещё gcc умеет рекурсивный inline.

aureliano15 ★★
()
Последнее исправление: aureliano15 (всего исправлений: 1)
Ответ на: комментарий от aureliano15

Он имеет в виду, что если тела функций (не шаблонные) описаны в хэдере, то их надо определять с inline, иначе получится редефинишн. При это это опять же не гарантирует инлайн, но избежать ошибки компиляции помогает.

Dudraug ★★★★★
()
Ответ на: комментарий от aureliano15

По крайней мере в gcc

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

Dudraug ★★★★★
()
Ответ на: комментарий от aureliano15

Сейчас ещё раз проверил более внимательно, и выяснил, что царь наврал. [...]

Продолжай наблюдения ^_~

d_a ★★★★★
()
Ответ на: комментарий от Dudraug

А, понял.

Но и в си я могу сделать то же самое, объявив их static. Правда, тогда, если они не будут инлайниться, код всё равно раздуется.

aureliano15 ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.