О языке ++C

Нашелся тут чудесный баг в KDE-шном DNG-конвертере. Вдруг, внезапно, перестал конвертировать, получаются совершенно ЧОРНЫЕ DNG.

Понятно, пишут в багрепорты digiKam-у, а дальше стрелки переводятся по кругу, ко мне (но LibRaw не менялась, в KDE все еще 0.13), к автору DNG Converter, все отпираются т.к. test cases работают.

И наконец виновник найден

Было:

  *output = ...some value...;
  *output++;
стало
  *output = ... some value...;
  ++(*output);
И комментарий к коммиту: use prefix operator

А я подозреваю, что исходно там было и вовсе:

  *output++ = ... some value...;
Проверять не стал, но предсказываю это.

Потом один доброжелатель разбил операцию на две, как умел, а второй, из ненависти к суффиксным инкрементам (или из желания подавить compiler warning), поменял на префиксный. Тоже, как умел.

Всех люблю: опенсорс, коллаборативную разработку по схеме "у семи нянек....", язык C/C++ тоже люблю.

Comments

> Проверять не стал, но предсказываю это.

Логично. *ptr++; -- не имеет смысла разыменование указателя, кто-то обратил на это внимание и придал этому смысл. Логично предположить, что изначально кто-то "соптимизировал" по запарке оставив разыменование указателя. Это как Дядя Фёдор писал письмо маме, а Шарик с Матроскиным ему помогали.

В-общем, я не могу приветствовать, когда в код лезет кто-то, кто не понимает что там делается.

вот уж, где плюсы - лишь наследуют...
Plain Vanilla C

И, кстати, таки GCC даёт предупреждение на "*output++;":

предупреждение: вычисленное значение не используется

P.S.: Когда-то устраивался в одну контору, спросил у будущего технического босса, а используется ли у них Open Source. Он ответил, что используем GCC, но предварительно отключаем у него все-все предупреждения, а то уж слишком много получается...

> но предварительно отключаем у него все-все предупреждения, а то уж слишком много получается...

Больше всего бесит, когда есть char* и unsigned char *, и gcc ругается на их смешивание. Так что есть у него ненулевое количество бесполезных, а иногда просто отвлекающих предупреждений. Есть много полезных, конечно.

Знаковый бит по разному тиражируется при преобразовании в int, а в int на каждом шагу, особенно в аргументах.

А какой именно знак у типа char? Если я использую char без указания знаковости, значит мне на неё просто плевать.

Приведение из char в unsigned int (и последующее использование в качестве индекса в массиве, например) добавляет веселых минут.

Есть библиотечные функции, которым совершенно пофиг на знаковость передаваемого char*, но вот компилятору становится не пофиг, как ты в основной программе знаковость указал, ругается. Ну и не только это. А веселуху с (unsigned)(unsigned char)*ptr надо один раз пройти, чтобы понять.

В int - нормально (было отрицательным и им и осталось). Веселуха с unsigned.

Может быть, кстати, автор коммита так вычищал предупреждение gcc

Ну так да, тут оба хороши одинаково. За то и люблю.

Есссно, главный вопрос в том, что из себя представляет output.

Там, скорее всего - только встроенные типы.
Для них - не так много разницы.

А плюсы стремятся предоставить это не только для встроенных типов.
Вот тут и начинается в Си++ "большАя разница-а-а-а"... (тут вот хорошо агент Смит говорит: "Но это всё - фигня! Кстати, у нас в Матрице - есть истории по-круче...")

Но этот пример ещё раз говорит о том, что ни на одном из языков - голову выключать не следует.

output, небось unsigned short * или что-то в этом духе.
А голова - самый важный прибор, туда же едят!

Вместе с тем, по первой ссылке для меня открылись бездны. Оказывается, тема prefix/postfix - это серьезная такая проблема, дискутируется, люди тесты пишут. Ужоснах.

Оказывается, тема prefix/postfix - это серьезная такая проблема, дискутируется, люди тесты пишут.

Дык, "unsigned short *" - это вам не std::map::const_iterator!

Или, вот участвовал я в разработке одной системы, там понадобилось для промежуточного представления (есть представление "нетронутое", а есть - "чуть подправленное") писать итератор (разные пользователи параллельно проходят: кто-то по прежнему представлению, кто-то уже по изменённому; кстати, итератор по изменённому представлению - блокирует изменение...).

Вы не поверите, но пришлось поднять под это одну скользкую тему.
Явный "эффект домино": хочешь изменить поведение стандартного алгоритма, который базируется на концепции итераторов (в твоём случае - встроенные типы), алгоритм - в стандартной области имён, у стандартной области имён особый статус - и понеслась...

По мне, так современный C++ вообще слишком сложен.

В частности, идея, что семантику простых типов (операторы, собственно) можно безболезненно *и эффективно* нести на сложные типы - мне кажется немножо неправильной. Хотя, понятно, многие вещи облегчает за счет code reuse.

> По мне, так современный C++ вообще слишком сложен.
Хм. Может быть, вам тема raw-форматов фотографий или параллельных вычислений на GPU - кажется более простой?
Думаю, язык этот сложен не потому, что авторам просто захотелось сделать его настолько сложным.
Суть в том, что если взять пользователей, сферу применения и решаемые задачи - и этот самый язык, который их объединяет, то окажется, что сложность тут не на ровном месте возникла.

Кстати, вот интересно, для чего, лично по твоему мнению, существует современный Си++?
Чтобы создавать KDE?
Чтобы делать обёртки для plain vanilla C библиотеки gtk+?

> идея, что семантику простых типов (операторы, собственно) можно безболезненно *и эффективно* нести на сложные типы - мне кажется немножо неправильной.
Я для себя понял, что этот вопрос - уже пройденный этап.
"Тема закрыта."
Другая тема, которая, вроде бы тоже "закрыта", но ещё "в работе" - это встраивание в язык концептов.

> многие вещи облегчает за счет code reuse
Даже не столько "reuse", сколько просто - "use".
(вот тут один британец очень хорошо закрыл эту тему - на 36:40)

Ещё в прошлом веке, один мой институтский товарищ умело интуитивно пользовался стандартными потоками и свято верил, что конструкции типа cout << "Hello, world!" << endl; - являются встроенной частью языка (т.е. не библиотека тебе поставляет cout, оператор << для потока и других типов, манипулятор endl, а именно язык Си++).

Я к тому, что если ты не писатель библиотек (а ты - писатель), то не все разделы языка тебе так уж обязательно знать для решения насущных задач.

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

Я написал длинно, а потом стер.

язык, который их объединяет, то окажется, что сложность тут не на ровном месте возникла

Ну, да, если мы хотим удобно писать драйверы, удобно программировать для GPU, удобно рисовать окошки и все такое... то получится PL/1. Который, типа, для всех.

Но с ним тоже прикольно. Лафа с single thread/scalar потоком исполнения - кончилась. А началось SIMD, гетерогенность (GPU/APU), multi-core, many-core. Ну не у всех началось, но у HPC и у мультимедии - в полный рост.
Что, тоже понесем это все в C++? Но ведь тогда совместимость *всего* наработанного тоже придется обеспечивать.

Не пора ли остановиться?

Ты извини, я - многословен бываю. :-)
Может сложиться впечатление, что я защищаю Си++.
У тебя есть знакомые, кто уже перешёл на Erlang и Haskell с Ocaml?
Звали тебя?

Ну сразу ужасы всякие, Haskell...
Куча народу работает (или перешла) на Javascript, PHP, Perl. Java, опять же. Процедурные такие. C# еще.

А с C++ предвижу такую же беду, как с Перлом - код, написанный одним разработчиком (на одном subset языка), будет совершенно нечитаем для другого.
И наоборот.
И перл сейчас известно где, хотя одно время он сильно выделялся именно по количеству библиотек (модулей) т.е. был сильно популярен.

Если говорит о корпоративной разработки...

Ну, Java и C# только выиграют от развития C++.

Со сравнением перл/С++ - мне очень сложно согласиться.
Это очень, очень грубое сравнение.

(кстати, корпоративная страничка стала содержать C++ программера, перловщик - так и не пропал)

Я вижу лишь перетягивание каких-то функций со статически типизированного C++ на какой-то динамически типизированный язык, тот же Python (хотя, он тоже содержит слишком много свободы выражения).

Ну что значит "выиграют"? Они уже выиграли от неразвитого C++, куда им еще?

Я вот имею перед глазами свежий пример. Вот хочется мультитредно, мультикорно и параллельно поменять местами элементы двух векторов. Автор берет Intel TBB и выписывает под это дело класс. С конструктором, operator (). Всякая шелуха (конструктор, описание членов класса и т.п.) занимает там ровно 50% по строчкам. А для более простой вещи, просто копирования, шелухи процентов 70.

Какая-то ерунда: хочешь эффективной сортировки - делай объекты с ленивым копированием, иначе сортировка тебе будет все копировать. Как-то с сортировкой массива указателей оно было попроще...

да уж - колоритно

Зыс ыс зы павар ов опэн сорц!!!

Преимущество опенсорса тут в том, что можно всем багу показать (автора ославить) и сказать "не надо так делать".

Можно глупый вопрос: а что это за технико-социальное явление, "ненависть к суффиксным инкрементам"?

Александреску, например, говорит о предположительно большей эффективности префиксных инкрементов. А это голова :)

Во, алаверды к Максиму, нашел на Stack Overflow:
===
Herb Sutter and Andrei Alexandrescu, C++ Coding Standards, p.50: "The prefix
form is semantically equivalent, just as much typing, and often slightly
more efficient by creating one less object. This is not premature
optimization; it is avoiding premature pessimization."
===
http://bytes.com/topic/c/answers/168681-why-prefix-increment-faster-than...

Но по идее, если значение не используется, то компилятор и объект не создаст для простых типов.
Для user-defined типов (со своим оператором) объект создаться должен в любом разе.

Может быть просто, как пишут выше, от compiler warning так избавлялись.

А, ага, для постфиксной формы нам надо скопировать объект, а для префиксной - достаточно вернуть референс на текущее состояние.