Pull to refresh

Comments 43

UFO just landed and posted this here

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

Когда модули будут повсеместными и можно будет парсить модули в отдельном режиме, возможно будет менять язык менее осторожно

UFO just landed and posted this here

Буст. Хотите вы того или нет, но если вы его используете, то компилируете под стандарт новее, чем тот, под который он писался

UFO just landed and posted this here

Мы недавно напоролись на то, что бинари скомпилированные на ubuntu 18.04 не работают на slackware 14 из-за того, что версия glibc на пару субверсий ниже

Вы путаете ABI совместимость и совместимость синтаксиса языка.

Это другая совместимость. Что космический корабль не компилируется со старыми опциями нормально.

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

Но все хотят чтобы старый код можно было скомпилировать под новый компилятор.

Это еще не самое сильное требование.

Еще в C и С++ заложено, что если какая-то библиотека (по сути архив из объектных файлов) была создана X лет назад, то она должна успешно линковаться с библиотеками и бинарниками, которые пишутся сейчас, и которые будут писаться через X лет.

Это называется Application Binary Interface, его нарушение сделало бы всем очень плохо.

Ну, а некоторые языки-"убийцы С++" балуются нарушениями своих собственных аналогов ABI, пока их использует 2.5 человека.

Вы кажется пропустили эпичный полом ABI в C++, когда изменился std::string

Спасибо! Я не знал про этот факт. Пишут, что поломали из-за того, что стандарт запретил CoW-строки - странное изменение стандарта. Еще бы name mangling занесли в стандарт, чтобы убить неугодные компиляторы...

Я уж не говорю о том что нет никакого стандарта на name mangling.

Для интереса посмотрел на How different compilers mangle the same functions: тут некоторые компиляторы каких-то лохматых годов, не хватает статистики по процентам пользователей (возможно, у 99-99.9% библиотек под Linux, mangling сейчас одинаковый). Но если прикинуть, что было 20-25 лет назад, и взять нечто, сбилженное в то время... Да, есть риск, что будет негодно к употреблению.

Тогда вся надежда на безпроблемную сборку из исходников с нуля.

Дело не в компиляторах 20-летней давности, проблема с манглингом C++актуальна сегодня как и раньше. Компиляторам приходится как-то договариваться об ABI, чтобы код, собранный разными компиляторами, мог взаимодействовать в рамках одной платформы. Но никакой заслуги C++ в этом нет. Например: https://bugzilla.redhat.com/show_bug.cgi?id=1435825 Обратите внимание, речь идёт о том чтобы сделать Clang "совместимым с GCC". Но не о том что "Clang неудовлетворяет стандарту C++".

Тогда вся надежда на безпроблемную сборку из исходников с нуля.

Это тоже не работает. Возьмите любой крупную программу на C++ и я уверен что найдёте коммиты вида "изменяем код, чтобы он стал совместим с новым стандартом C++".

----

Мой посыл в том что C++ вообще не специфицирует ABI.

поломали из-за того, что стандарт запретил CoW-строки - странное изменение стандарта

Начнём с того, что CoW строки ни когда не описывались в стандарте, а были на совести авторов конкретной реализации STL.

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

Это выглядит неправильно, комитет не должен исправлять неудачные решения в частных реализациях STL за счёт правок в стандарт (как попробовали со std::string в C++11).

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

Тянули бы CoW-строки до 2040 года - их выбор

Или вы не понимаете разницы между однопоточным и многопоточным приложениями или не понимаете проблем с CoW. Была явно запрещена опасная для многопоточных приложений оптимизация библиотеки.

Вместо этого комитет стандартизировал small/short strings optimisation, безопасные для многопоточки.

Или вы не понимаете разницы между однопоточным и многопоточным приложениями или не понимаете проблем с CoW.

Вы меня не так поняли - я за отмену CoW, но предпочел бы, чтобы это делал сам GCC (и прочие, к кому относится) без пинков от комитета.

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

Но это личная точка зрения.

Вы меня не так поняли - я за отмену CoW, но предпочел бы, чтобы это делал сам GCC (и прочие, к кому относится) без пинков от комитета.

Я вас понял, но проблему с CoW строками вы всё же не понимаете. Данная оптимизация абсолютно легальная для С++98/03, так как язык сам по себе был однопоточный и вся многопоточность была "отдана" программистам by design. В С++11 внесли многопоточность как часть языка и логично, что изменились требования к реализациям. Ни кого же не смущает требование произвольного доступа в массивах со сложностью О(1), или линейное расположение данных той же строки в памяти?

И да, CoW использовала далеко не только STL реализованная в GCC. Если правильно помню те же Микрософт использовали строки с CoW в STL до VC++ 6.0 (включительно), но уже в VC++ 7.0 отказались, задолго до изменений стандарта.

Ну и версий STL великое множество, не привязанных к компилятору, STLPort (не актуально, так как проект умер, но одно время эта версия была очень популярна), Apache STDCXX, коммерческая Dinkum STL и её реализации для QNX (C++03, C++11), ElectronicArts STL, Microsoft STL, Embedded STL и ещё куча, которых сразу и не вспомнишь.

Поэтому шаг комитета о явном запрете оптимизаций, которые не вписываются в новый стандарт совершенно логичен, а хейтеры были и будут всегда. Вспомните хотя бы историю с оптимизированной версией memcpy в glibc сломавшей flash плеер и youtube у всех пользователей Linux? А ведь там разработчики в принципе ни чего не меняли, что бы не было прописано в стандарте, но выяснилось, что многие полагались на фактическое, а не стандартное поведение.

UFO just landed and posted this here

Это не совсем так, C++11 компиляторы ввели Dual ABI, с C++17/20 все становится сложнее но возможность использовать Old ABI все равно есть, так что в принципе возможность запускать программы 20 летней давности на современных ОС сохраняется (на усмотрение мейнтейнеров ОС)

UFO just landed and posted this here

Это не является частью стандарта. Если вы собираете C++11-компилятором код с совместимостью строк с C++03, то компилятор вам на самом деле врёт.

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

Ну ок, куда мне здесь нажать, чтобы имена в центральном окошке манглились так же

Никуда. С++ обеспечивает обратную совместимость, т.е. вы всегда можете писать новый код который будет работать со старым, поддержки старым кодом новых фич нет. Никто не заявлял гарантию что компиляция старого кода новым компилятором даст тот же результат. Однако при необходимости обеспечить совместимость вы можете путём корректировки исходников.

Ну так у современных ОС «сишный ABI», ещё бы.

Ну очевидно же что я имел ввиду системные библиотеки завязанные на С++, такие как glibc а не интерфейсы ОС. И у современных ОС не "сишный" интерфейс - SYSCALL в СИ программах никто не дёргает.

ABI поменялся в C++17 (noexcept стал частью сигнатуры, и, как следствие, mangled-имени) и в C++20 (requires с концептами). Пока что количество релизов C++, где ABI ломали, больше, чем тех, где не ломали.

С++20 ABI не ломает - его фичи на предыдущих версиях вообще не работают, так что 1 поломка (noexcept) которая многими замечена вообще не была (не самая популярная фича, хоть и зря) и поломка строк/листов в С++11 для которой есть решение сохраняющее обратную совместимость. 1.5 из 6 стандартов за 22 года.

UFO just landed and posted this here

хотя считать ли багфикс-релиз C++03 отдельным стандартом — вопрос спорный

ПРосто к слову, многие (и я склонен согласиться с этим мнением) считают С++14 тоже баг-фиксным релизом для С++11.

UFO just landed and posted this here

Ну не будем, так не будем.

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

При такой цели стоит выбрать другой язык программирования, в C++ это не работает на практике.

У меня в этом плане опыт с с++ нормальный, по крайней мере гораздо лучше чем переход с Питон 2 на 3.

А что у вас ломалось?

Интересно, но патчить компилятор это довольно лихо! Интереснее для более широких публики я думаю как писать какие-то расширения по типу qt-moc, на основе libclang.

Практичнее было бы написать класс, вызывающий в деструкторе переданную лямбду.

#include <iostream>
#include <functional>
using std::cout;
using std::endl;

class defer {
   std::function<void()> _t { []() {} };
   defer() {};
public:
   explicit defer( std::function<void()> t ) :_t( t ) {};
   ~defer() { _t(); };
};

int main() {
   int i = 0, *m = new int[ 123456789 ];

   defer d0 { [&] { cout << "deferred 0 i: " << i << endl; i = 3;  m[ i ] = i; delete[] m; } };

   defer d1 { [&] {
      int j = 0;
      defer di { [&] { cout << "inner deferred i: " << i << endl; i = 8; m[ i ] = i; } };
      cout << "deferred 1 j: " << j << endl; j = 1;  m[ j ] = j;
   } };
   
   cout << "hello" << endl;
   defer d2 { [&] { cout << "deferred 2 i: " << i << endl; i = 2; m[ i ] = i; } };
   cout << "world!" << endl;

   // auto error = new defer;
   // auto error = defer();
   // defer error;
   // defer error {};
}

2 минуты и буст не нужен.

Лучше лямбду хранить не в std::function а в темплейт параметре.

Так пойдёт?

template< typename T = std::function<void()> >
class defer : T {
   defer() {};
public:
   explicit defer( T t ) : T( t ) {};
   ~defer() { (*this)(); };
};
UFO just landed and posted this here

Это слишком просто и, думаю, не нужно.

template< typename T >
class defer {
   T _t;
   defer() {};
public:
   explicit defer( T t ) : _t( t ) {};
   ~defer() { _t(); };
};
UFO just landed and posted this here

Для бустового defer-а такой сценарий использования не предусмотрен, поэтому там жёстко зашито &.
Захват по значению компилятор отвергает, ессно.

Бустовые макросы это что-то из времён до С++11.

UFO just landed and posted this here

а если ещё вспомнить про правило трёх/пяти и forward в конструкторе... плюс не думаю что стоит тут наследовать потому что вряд ли есть смысл вызывать функцию явно... а и по новым гайдлайнам вместо приватного конструктора наверное надо делать = delete.

defer с разным успехом имитировали в существующих проектах «руками».

defer в Go вызывается при выходе из функции. ~auto() вызывается при выходе из области видимости.
play.golang.org/p/Iw9SZNjSUQH

Надо менять в компиляторе функции как делали с корутинами.

Спасибо, очень интересно. Как я понимаю, через plugin для clang добавление нового ключевого слова не провернуть?


Я выбрал release-сборку -DCMAKE_BUILD_TYPE=Release, так как debug-символов будет столько, что бинарник clang скорее всего не слинкуется (процесс линкера убивается по Out-Of-Memory после пожирания всей оперативки)

В моём случае помог -j1 но ценность дебаговой сборки весьма сомнительна — огромное кол-во отладочной информации грузится ну оочень долго.

через plugin для clang добавление нового ключевого слова не провернуть?

К сожалению не выйдет, в статье имитируется изменение самого языка, как если бы в стандарт добавили новое ключевое слово.

Но сами плагины тоже супер мощные, и с помощью них можно форматировать код (clang-format), фиксить простые ошибки (clang-fixit), рефакторить, делать линтеры (которые ищут опасные паттерны и предлагают их убрать). Это вспомогательные программы.

Выше пишут, что на libclang сделан qt-moc. Судя по описанию, эта надстройка ищет макрос внутри класса и генерирует по нему исходник. Я не разбираюсь в Qt, не могу сказать правда ли так, но теоретически это возможно.

Выше пишут, что на libclang сделан qt-moc.

Нет, не на нём. (См. здесь )

Sign up to leave a comment.

Articles