Здравствуйте, Worminator X, Вы писали:
WX>Так, то есть указатели нужны там, где связанный объект может меняться (при обходе по циклу, например)? А ссылки всегда иммутабельные после первого присваивания?
Да, примерно так. Проще всего представлять себе ссылку, как особый вид указателя, инициализированный с const, и автоматически разыменуемый при каждом использовании. Теоретики C++ утверждают, что такая аналогия лишь приблизительна, но я не слышал, чтобы технически это где-то работало иначе.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Я вообще не вижу ни одного преимущества чистого C перед C++, кроме некоторого синтаксического сахара, добавленного в C в процессе параллельного развития с C++. Все, что написано на C, можно переписать на C++, и это будет более компактно, более понятно, более надежно и не менее эффективно. Но вот это откровенно дурацкое убеждение "не используя шаблонную магию, вы не используете C++" настолько прочно засрало всем мозги, что изучение C++ часто начинают именно с нее. Адекватно понять эти нечеловеческие конструкции без глубокого понимания ядра языка невозможно, поэтому большинство их тупо заучивает, и применяет где по шаблону, где по аналогии, а где просто интуитивно.
ЕМ>А если не стремиться следовать модным трендам, и использовать C++ в том объеме, который реально необходим для задачи, он у C только выигрывает.
В какой-то мере соглашусь. Преимущества Си вижу в том, что всегда понятно, во что компилируется код, и как он будет выполняться (что неудивительно для кроссплатформенного ассемблера, как он планировался). Если, конечно, не использовать кулхацкерские UB трюки вроде инкрементов внутри выражения (классический пример копирования строк из K&R — while((*dest++) = (*src++)); ) и не злоупотреблять макросами (я их использую только для констант, коротких inline-функций и условной компиляции). Ограниченное использование C++ в целом может немного повысить читаемость и избавить от лишних скобок и зведочек, плюс паттерн RAII удобно реализуется через конструкторы/деструкторы. Шаблоны удобны для обобщенных коллекций, но вычислять факториалы на них сомнительная идея. Перегрузка операций имеет смысл, например, для тех же потоков cin/cout или для сложения матриц/конкатенции строк, но перегружать скобки и запятые это полная шиза (очень разумно, ИМХО, было реализовано в C#).
Вообще давно задумывался над идеей создания этакого языка "Си-плюс-минус". Где, с одной стороны, были бы классы из C++ (без шаблонов или с type erasure как в Java, кастом в void*) и некоторые другие возможности из ранних версий, а с другой, были бы низкоуровневые фишки, например, доступ к регистрам через псевдопеременные вроде $EAX. Но при бездумном проектировании есть шанс породить монстра вроде PHP. Нужно глубоко погружаться в тему проектирования компиляторов, формальных грамматик и т.д., стать вторым Никлаусом Виртом.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
Здравствуйте, Worminator X, Вы писали:
WX>Так, то есть указатели нужны там, где связанный объект может меняться (при обходе по циклу, например)? А ссылки всегда иммутабельные после первого присваивания?
Все правильно, ссылка связывается с каким-либо объектом и остается к нему привязанной все свое время жизни. В определенных случаях ссылки даже могут продлевать время жизни временных объектов, к которым они привязаны. И С++ запрещает создание непривязанных ссылок. Все, без исключения, операции со ссылкой имеют строго такой же эффект, как если бы все эти операции выполнялись непосредственно над объектом, к которому эта ссылка привязана. Основная практическая польза от использования ссылок состоит в том, что программист избавлен от необходимости проверять ссылку на null, как в случае с указателями, ибо требования стандарта языка таковы, что в корректной программе не может появиться ссылки, привязанной к нулевому адресу. Единственная проблема, которая лежит на плечах программиста — держать под контролем время жизни ссылок и объектов, на которые эти ссылки ссылаются. Нет никакого криминала в том, что время жизни объекта закончится раньше, чем время жизни ссылки. Но программист должен исключть возможность использования таких "висячих" (dangling) ссылок после окончания времени жизни объекта. Достигается это обычно путем продумывания дизайна.
В отличие от ссылки, указатель — это объект (переменная), хранящая адрес другого объекта. Подобно обычной целочисленной переменной, значение адреса, записанное в указателе может изменяться и сбрасываться в null. Одно из полезных применений указателя мы уже упомянули — это использование его в качестве итератора по последовательностям, занимающим непрерывные области памяти. Другое частое применение логически можно обозначить как "необязательная ссылка". Т.е. ссылка на необязательный объект, который может отсутсвовать. Перед использованием указателя для доступа к адресуемым данным, необходимо проверить его на null.
Здравствуйте, Worminator X, Вы писали:
WX>Преимущества Си вижу в том, что всегда понятно, во что компилируется код, и как он будет выполняться
Это в полной мере верно и для C++ в формате "C с классами", без исключений и некоторых относительно новых возможностей. Хотя те же анонимные функции технически весьма просто и экономично заворачиваются в классы, в коде вызов выглядит прозрачно.
WX>Шаблоны удобны для обобщенных коллекций, но вычислять факториалы на них сомнительная идея.
Апологеты шаблонной магии с Вами не согласятся. Для них всё, что технически реализуемо на шаблонах, должно быть реализовано именно на них, иначе это "не настоящий C++". Если же у кого мозги не заточены под то, чтобы свободно мыслить в терминах этой извращенной кухни, то он "недостаточно владеет языком".
WX>Перегрузка операций имеет смысл, например, для тех же потоков cin/cout
Да, кстати, еще один бзик апологетов "истинного C++" — стремление весь текстовый ввод-вывод делать непременно на потоках. Если где увидят функции типа *printf — это опять "не настоящий C++".
WX>Вообще давно задумывался над идеей создания этакого языка "Си-плюс-минус". Где, с одной стороны, были бы классы из C++ (без шаблонов или с type erasure как в Java, кастом в void*) и некоторые другие возможности из ранних версий, а с другой, были бы низкоуровневые фишки, например, доступ к регистрам через псевдопеременные вроде $EAX.
Не взлетит. Кода, требующего вылизывания с точностью до регистра и такта, ничтожно мало, его можно писать хоть на ассемблерах, хоть на готовых языках вроде C--. Для ООП разумной сложности есть базовый C++. А реализация сколько-нибудь достойного метапрограммирования, хоть на шаблонах, хоть на макросах, вместе с сопровождением, потребует ресурсов, неадекватных для одиночки или небольшой команды, а заинтересовать этим сколько-нибудь крупный и стабильный коллектив или сообщество не выйдет.
Более реалистичным мне видится создание языка, который можно было бы относительно несложно транслировать в "базовый" C++.
Здравствуйте, пффф, Вы писали:
П>В Си нет никаких виртуальных методов. Но упоротые делают их на указателях на функцию. Типа Гобжектов
Виртуальную таблицу можно реализовать вручную через поле структуры, получается что-то вроде point->vtable->moveTo(&point, x, y); Примерно так сделано во всех этих GObject/NSObject/IUnknown. Только при наследовании (а иначе зачем виртуальные методы?) код становится большим и нечитаемым, поэтому такого лучше избегать. ООП без виртуальных методов — это просто функция с дополнительным параметром this, т.е. Point_moveTo(&point, x, y); — в таком виде на Си можно писать без каких-либо проблем, и практически все стандартные библиотеки это используют. Фактически принципы классического ООП (инкапусляция/полиморфизм/наследование) это более удобное дополнение обычных функций, работающих с ресурсами, вроде fprintf. ООП должно упрощать процедурный код, а не усложнять. Ну и реализуется оно разными подходами, где-то достаточно просто структуры с this, где-то лучше на классах из Симулы, где-то лучше SmallTalk/Objective-C/Swift с рефлексией, а где-то прототипное на хэш-таблицах как в Lua/JavaScript.
П>Хм, месье знает толк в извращениях
Все эти языки (Java, C, Asm) очень просты, понятны и удобны для задач различного уровня. Работа с сетью и БД на Java, прикладные библиотеки для Си (WinAPI, OpenGL, SDL и др.), низкоуровневые вещи на Асме. При этом везде сохраняешь полный контроль, насколько можно. Извращения — это отвратительный JavaScript с его автоматическими преобразованиями (на кой черт они нужны? В Бейсике вот были STR/VAL/INT, и всех устраивало) или упомянутая выше шаблонная магия в C++. Все то, что затрудняет понимание и превращает программиста в вархаммерского техножреца. Современный C++ пытается конкурировать с высокоуровневыми языками Java/C#, с рефлексией, модулями, автоматическим управлением памятью и т.д., при этом сохранять совместимость с Си, вот это и есть извращение. Один язык не должен иметь функциональность Java (а сейчас скорее даже Scala) и ассемблера одновременно. Каждой задаче свой инструмент. Вот есть, например, SQL и язык регулярных выражений — они просто делают свою работу. А извращенцы пишут вещи вроде JOOQ.
Как запру я тебя за железный замок, за дубовую дверь окованную,
Чтоб свету божьего ты не видела, мое имя честное не порочила…
М. Лермонтов. Песня про царя Ивана Васильевича, молодого опричника и удалого купца Калашникова
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>А толку? Чисто языковые возможности C++ и шаблонная магия практически ортогональны друг другу. Более того, после вдумчивого изучения и использования "базового" C++, шаблонная магия способна вызывать стойкое отвращение.
Два ниасилятора нашли друг друга чтобы доказать самим себе, что их ниасиляторство -- это нормально.
Здравствуйте, Worminator X, Вы писали:
П>>В Си нет никаких виртуальных методов. Но упоротые делают их на указателях на функцию. Типа Гобжектов
WX>Виртуальную таблицу можно реализовать вручную через поле структуры, получается что-то вроде point->vtable->moveTo(&point, x, y); Примерно так сделано во всех этих GObject/NSObject/IUnknown. Только при наследовании (а иначе зачем виртуальные методы?) код становится большим и нечитаемым, поэтому такого лучше избегать. ООП без виртуальных методов — это просто функция с дополнительным параметром this, т.е. Point_moveTo(&point, x, y); — в таком виде на Си можно писать без каких-либо проблем, и практически все стандартные библиотеки это используют. Фактически принципы классического ООП (инкапусляция/полиморфизм/наследование) это более удобное дополнение обычных функций, работающих с ресурсами, вроде fprintf. ООП должно упрощать процедурный код, а не усложнять. Ну и реализуется оно разными подходами, где-то достаточно просто структуры с this, где-то лучше на классах из Симулы, где-то лучше SmallTalk/Objective-C/Swift с рефлексией, а где-то прототипное на хэш-таблицах как в Lua/JavaScript.
Я про то и говорю. Можно гобжектами, а можно нормально красиво на плюсиках
П>>Хм, месье знает толк в извращениях
WX>Современный C++ пытается конкурировать с высокоуровневыми языками Java/C#, с рефлексией,
С рефлексией вроде не пытается, но я мог что-то пропустить
WX>модулями,
Модули — это какая-то хрень, кто-то их возлюбил, но я пока обожду.
WX>автоматическим управлением памятью и т.д.,
Нет. Автоматическое управление памятью — это совсем не мусорщик
WX>при этом сохранять совместимость с Си, вот это и есть извращение. Один язык не должен иметь функциональность Java (а сейчас скорее даже Scala) и ассемблера одновременно.
Не вижу причин иметь все возможности, которые можно использовать по своему усмотрению
WX>Каждой задаче свой инструмент. Вот есть, например, SQL и язык регулярных выражений — они просто делают свою работу. А извращенцы пишут вещи вроде JOOQ.
Здравствуйте, Worminator X, Вы писали:
WX>Вообще давно задумывался над идеей создания этакого языка "Си-плюс-минус".
Ты плюсики не осилил, а уже собрался что-то проектировать?
WX>Где, с одной стороны, были бы классы из C++ (без шаблонов или с type erasure как в Java, кастом в void*)
Без шаблонов — это кал.
Java — тоже кал
WX>и некоторые другие возможности из ранних версий, а с другой, были бы низкоуровневые фишки, например, доступ к регистрам через псевдопеременные вроде $EAX.
На арме нет такого регистра. Как быть?
WX>Но при бездумном проектировании есть шанс породить монстра вроде PHP. Нужно глубоко погружаться в тему проектирования компиляторов, формальных грамматик и т.д., стать вторым Никлаусом Виртом.
Никлаус Вирт — неудачник, но тебе до него далеко )
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Не взлетит. Кода, требующего вылизывания с точностью до регистра и такта, ничтожно мало, его можно писать хоть на ассемблерах, хоть на готовых языках вроде C--. Для ООП разумной сложности есть базовый C++. А реализация сколько-нибудь достойного метапрограммирования, хоть на шаблонах, хоть на макросах, вместе с сопровождением, потребует ресурсов, неадекватных для одиночки или небольшой команды, а заинтересовать этим сколько-нибудь крупный и стабильный коллектив или сообщество не выйдет.
На шаблонах и constexpr'ах можно писать очень эффективный код
Здравствуйте, Worminator X, Вы писали:
WX>Мда, сложно как-то. Ну его на фиг, этот C++, лучше чистый Си с указателями и Java для ООП.
ООП у плюсов сильнее, чем у джавы. Но метаооп у джавы сильнее, потому что есть рефлексия. Это с тз языков.
С тз применимости ты вообще чушь написал. Не везде ты бесплатно воткнешь Джаву.
WX>А списки хотел сделать именно иммутабельными (вообще это попытка написать свой интерпретатор Лиспа, там было более сложное наследование с атомами и списочными парами).
В твоем варианте иммутабельность слишком жестокая. Она и в рантайм, и в компайл тайм. У тебя нельзя составить произвольный иммутабельный список. Можно только тот, который еще и в компайл тайм фиксирован.
WX>Ссылка — это некий аналог #define макросов для компилятора, получается?
Нет, совсем не получается. Видишь ссылку — подразумеваешь алиас. Алиас больше, чем разыменованный указатель.
Здравствуйте, Worminator X, Вы писали:
WX>Для чего тогда вообще в C++ нужны ссылки? Какую задачу они решают? Если все равно приходится использовать указатели, то достаточно моего 2-го кода с new/delete.
Не думаю, что будет здесь кто-то писать простыню о том, зачем они, и чем они лучше или хуже. Если ты говоришь, что пытаешься освоить плюсы, то берешь плюсы и пишешь исключительно на указателях.
Как только возникнет желание заиспользовать ссылку, делаешь отметку себе в блокнот почему. Своей практикой дойдешь, зачем и когда они лучше, чем указатели.
Потом по блокноту напишешь статью для новичков. До сих пор никто этого не сделал в полной мере...
WX>Для чего тогда вообще в C++ нужны ссылки?
Думаю так, но может кто поправит:
Был C и у него была арифметика указателей, которая была завёрнута на арифметические операторы.
Потом добавили классы и получился C++, в котором решили разрешить перегружать арифметические операции,
что потребовало синтаксически нового способа доступа к методам класса.
Поэтому ввели ссылки, в которых выполняются только объектные перегрузки операций c тем же синтаксисом арифметических операций.
WX>Какую задачу они решают?
Открывают доступ к методам объекта и перегруженным операциям объекта.
WX>Если все равно приходится использовать указатели, то достаточно моего 2-го кода с new/delete.
Могу ошибаться, но в C++ "голые" указатели встречаются, обычно, только в низкоуровневых интерфейсах обменах данными.
А дальше передаются в прикладной код уже "умные" указатели и контейнеры.
C++ — язык, который позволяет писать в рамках разных парадигм программирования:
процедурной, объектно-ориентированной, обобщённой, функциональной. /*Каждая тянет на внушительную книжку.*/
И можно их комбинировать в проектах, а можно и какими-то возможностями не пользоваться.
Но некоторые реализации в некоторых случаях будут более эффективными, чем другие.
Здравствуйте, пффф, Вы писали:
П>На шаблонах и constexpr'ах можно писать очень эффективный код
Можно. На constexpr'ах — даже нужно. А вот на шаблонах это делают исключительно от убожества языка. Такого сочетания пафоса и упертости с крайней бедностью выразительных средств еще поискать надо.
Здравствуйте, Евгений Музыченко, Вы писали:
П>>На шаблонах и constexpr'ах можно писать очень эффективный код
ЕМ>Можно. На constexpr'ах — даже нужно. А вот на шаблонах это делают исключительно от убожества языка. Такого сочетания пафоса и упертости с крайней бедностью выразительных средств еще поискать надо.
Такое сочетание пафоса и упёртости можно легко найти у вас, Евгений
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Но вот это откровенно дурацкое убеждение "не используя шаблонную магию, вы не используете C++" настолько прочно засрало всем мозги, что изучение C++ часто начинают именно с нее.
Ни разу не слышал такого убеждения.
Постоянно езжу по стране, бывал во множестве организаций, где используется C++, — не встречал там такого.
По-моему это какая-то специфика исключительно вашего окружения.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Можно. На constexpr'ах — даже нужно. А вот на шаблонах это делают исключительно от убожества языка. Такого сочетания пафоса и упертости с крайней бедностью выразительных средств еще поискать надо.
Твое мнение было бы интересно, если бы ты добился хоть каких-нибудь успехов/результатов в той области, о которой рассуждаешь. А пока только очевидно, что лиса ругает виноград, до которого не дотянулась.
Здравствуйте, wander, Вы писали:
W>Постоянно езжу по стране, бывал во множестве организаций, где используется C++, — не встречал там такого.
Там, где C++ используют в первую очередь для разработки продуктов, имеющих реальный спрос, упертости и не должно быть. Я говорю главным образом о теоретиках, продвигающих идеологию языка — именно они задают массовые тренды.
W>По-моему это какая-то специфика исключительно вашего окружения.
У меня нет физического окружения из коллег — я всю жизнь работаю в одиночку, и с коллегами общаюсь исключительно в сетевых сообществах. И везде, в том числе и здесь, стоило упомянуть, что я не люблю шаблонной магии и не пользуюсь ею, как сразу же в ответ шли заявления вида "так это у тебя не C++, а C с классами", "это не настоящий C++" и т.п.
Здравствуйте, rg45, Вы писали:
R>Твое мнение было бы интересно
Оно "кому надо" и так интересно. То, что оно неинтересно конкретно Вам или еще кому-либо, ничего не меняет, ибо такой цели никогда не ставилось.
R>если бы ты добился хоть каких-нибудь успехов/результатов в той области, о которой рассуждаешь.
Да-да, слышали уже: "о вкусе овощей и фруктов имеет право рассуждать лишь тот, кто их выращивает профессионально".
R>А пока только очевидно, что лиса ругает виноград, до которого не дотянулась.
И не дотянется, ибо желания нет тянуться к технически убогим решениям, сколь бы математически изящными они не выглядели.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Оно "кому надо" и так интересно.
Ну и кому, напрмер?
R>>если бы ты добился хоть каких-нибудь успехов/результатов в той области, о которой рассуждаешь. ЕМ>Да-да, слышали уже: "о вкусе овощей и фруктов имеет право рассуждать лишь тот, кто их выращивает профессионально".
Исказил смысл. Речь шла о "хоть каких-нибудь" результатах. О "профессионально" речи не шло и близко.
ЕМ>И не дотянется, ибо желания нет тянуться к технически убогим решениям, сколь бы математически изящными они не выглядели.
Ну, именно так и говорят все лисы, которые не дотянулись до винограда.