Pull to refresh

Comments 82

Общие фразы это конечно хорошо, но нам бы в код пофтыкать…
В планах еще 4 статьи на заданную тему. Делать один, но очень громоздкий пост не хотелось — пошли поэтапно. Так что дальше будет больше мяса, в которое можно повтыкать)
Да там и с общими фразами не всё хорошо. Посмотрите на первый абзац: «Зачем что-то делать со своим кодом?! Ведь С++ кроссплатформенный язык!» — и дальше обсуждение того, что это правда — но не совсем правда.

Так вот: это совсем неправда. C++ — не был задуман «кроссплатформенным языком». Огромное количество способов сделать программу непереносимой. Начиная с того, что никому незвестно априори — влезет ли -1 в char или нет.

Однако он предназначен для написания кроссплатформенного кода. Но… только и исключительно в случае когда программист использует его «правильно». В этом — принципиальное отличие от Java или, скажем, Go.
Не соглашусь с вами. Все правила в Стандарте С++ формулируются в терминах абстрактной виртуальной машины, нигде не фигурируют завязки на конкретную программную или аппаратную платформу, то есть формально он является кроссплатформенным. Да и исторически С++ изначально проектировался переносимым, об этом пишет Страуструп в своей книге «Дизайн и эволюция С++» (глава 3.2 «Цели С++»):

… необходимо было дать ответ на несколько ключевых вопросов:
* кто будет пользоваться языком?
* на каких системах будут работать пользователи?

Чтобы ответить на второй вопрос, я просто огляделся по сторонам — на каких системах реально использовался C with Classes? Практически на любых: таких маленьких, что на них и компилятор-то не мог работать, до мейнфреймов и супер-компьютеров. Среди ОС были и такие, о которых я даже не слыхивал. Отсюда следовали выводы, что высокая степень переносимости и возможность выполнять кросс-компиляцию абсолютно необходимы…
strlen(«Хабр») в программе, собранной на MSVS выдаст 4; в GCC — 8.

насколько я знаю ни один из них не то что не выдаст, но даже не скомпилирует эти ваши ёлочки

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

Ещё и компилятор зануда, да.
Была б возможность — сам починил бы все опечатки, пропущенные запятые и прочие косяки, которые периодически обнаруживаются мной в статьях.
Статью оценил, но вот такая мелочь мозолит мои дотошные глаза. Профессиональное искажение и все такое. Слишком привык искать ошибки. Темная сторона силы она такая. Я твой отец, Люк.

Знаете, я многому учился по книгам и разное видел. Видел программы которые и с «string» работают и с 'string' работают. Одно из двух или вместе. Однажды я натолкнулся на то, что пример простейший на дюжину строк не работает. Потратил уйму времени, психовал. В общем, буря эмоций. К сожалению, среда говорила, что есть ошибка — а какая и где не говорила. Оказалось, что именно там тексты заключаются только в `string` такие кавычки, которые на букве ё висят. Кто же знал?
Так что да — иногда форма кавычек важна.
UFO just landed and posted this here

Не силён в Java, ничего криминального не увидел.

UFO just landed and posted this here
К приведенным рекомендациям можно добавить еще одну: при разработке кроссплатформенного кода желательно под все поддерживаемые платформы далать сборки регулярно и не давать ветке под какую-то одну платформу «вырваться» вперед — это минимизирует усилия по поддржке платформ. Так же желательно добавить хоть какое-то более-менее адекватное юнит-тестирование и построить процесс непрерывной интеграции — это все на начально этапе потребует дополнительных ресурсов, но в дальнейшем полностью окупится.
Не могли бы вы пояснить, что за СБИС? А то кроме Сверх Больших Интегральных Схем на ум ничего не приходит.
Вот в этом видео рассказывается про Тензор и Сбис
https://youtu.be/jqxxZIkzi80

СБИС = Система Бухгалтерской И Складской отчетности.


P.S. Почему бы не написать сразу, если знаете? Зачем давать сслыку на тупой промо ролик?

Изначально СБИС — Система бухгалтерского и складского учета. Название осталось прежнее, а система выросла. Поэтому СБИС мы не расшифровываем. Что такое СБИС, и какие представляет сервисы, можно посмотреть на сайте системы

Классно было бы куда-нибудь забить эту расшифровку. Например, вместо подписи "пользователь" в профиле. Слишком сильна ассоциация с интегральными схемами.

Уверен, что работа проведена масштабная, хочется почитать остальные статьи, но… Зачем вы переизобрели Qt? В крайнем случае могли бы его форкнуть и развивать, но вот так… Честно сказать я офигел))


PS: для кроссплатформенной работы с сетью есть обычные сокеты. Curl немного облегчает задачу, но вы ведь все делаете по хардкору)

Ах да, еще pimpl вместо ifdef хорошо бы использовать

Выбрать подходящую имплементацию во время сборки можно по сути только двумя способами:

1. через ifdef, например:

#ifdef LINUX
#  include <my_class_linux_impl.h>
#elif defined WIN32
#  include <my_class_win32_impl.h>
...

2. В сборочном скрипте, например, в cmake как-то так:

if (LINUX_OS)
   SET(IMPL_FILES my_class_lunux_impl.cpp)
elseif (WIN32_OS)
   SET(IMPL_FILES my_class_win32_impl.cpp)
...
endif ()
add_library(TestLibrary ${IMPL_FILES} another_file1.cpp another_file2.cpp)

Не понятно, как вам поможет идиома pimpl для выбора в compile time необходимой реализации. Все равно вам придется выбрать на этапе сборки одну из реализаций, подходящую под целевую систему, одним из вышеперечисленных способов.
Более того, не вижу противоречий в тексте статьи, ведь никто не предлагает писать вот такой вот плохокод:

void some_function()
{
#ifdef WIN32
CallWinAPIMethod();
#elif defined POSIX
CallPOSIXMethod()
#endif
CallAnotherMethod();
#ifdef WIN32
CallAnotherWinAPIMethod();
#elif defined POSIX
CallAnotherPOSIXMethod()
#endif
}

Мы знаем и активно используем паттерны проектирования (в том числе и pimpl). ifdef'ы используем только для выбора подходящей имплементации.

Вы забываете про фатальный недостаток (NIH).

Qt — тяжёлая и объёмная штука. Например, мы используем Qt исключительно для «тонкого» UI на Win / Mac / Linux, а для работы с сетью и с файловой системой у нас свои несложные классы-обёртки, которые абстрагируют особенности платформы и работают, кроме вышеуказанных систем, на Android и iOS. Не буду утверждать, что это наилучший подход, или даже рекомендовать его другим, но он меня вполне устраивает. В итоге, у нас минимум зависимостей от сторонних библиотек и максимум легко портируемого кода, который требует наличия только stdlib и системных API.
Вот уже не первый раз вижу полное не понимание Qt.
Уже с 4 версии он совсем не GUI-библиотека. Это полноценный кроссплатформенный фреймворк.
По поводу объемности — снова незнание структуры Qt. Как раз ваши классы обертки можно полностью заменить QtCore. Получив из коробки платформонезависимый код (работающий так же на Android и iOS) для файловой системы, unicode-строк, многопоточности и много еще что. Причем оверхед там минимальный. Я бы еще понял что вы C++14 используете там наконец много такое появилось (потоки и файлы).
В виде бонуса с Qt — вы получаете сигналы/слоты и классы для организации собственных структур данных (я про QSharedData и т.п.).
Я достаточно хорошо понимаю Qt, включая всё, что вы перечислили. Решение отказаться от Qt везде, кроме UI, принято с учётом этого знания.
Так раскройте причины такого решения. Ибо единственные вами указанны — размер(решается модульностью) и минимум зависимостей(а как же зависимость от того же Qt для GUI).
Реальная минимизация зависимостей возможна при отказе от кроссплатформенности (писать на MFC/WinAPI например). Иначе сразу возникает дублирование уже имеющегося — что по настоящему очень мало когда действительно требуется.
Размер в мегабайтах меня совершенно не беспокоит, по крайней мере применительно к Qt (нужные мне модули весят 10-20 МБ). Пожалуй, не стоило использовать слово «размер». Я имел в виду сложность самого фреймворка и его инфраструктуры, а не объём итоговых бинарников.
Основная причина: завязываясь на Qt, вы теряете кросс-платформенность за рамками списка поддерживаемых систем. И очень сложно потом переделать на что-то другое. Мне однажды довелось выпиливать Qt из бизнес-логики проекта, написанного на Qt, больше не хочу. Это понадобилось для запуска на платформе, которую Qt не поддерживал.
Вторая причина — доступность Qt на мобильных платформах, или, по крайней мере, на Андроид (насчёт iOS не знаю деталей) достаточно условна. Да, примеры там собираются и работают. А что, если у меня своё приложение со своими Java-UI и нативной библиотекой? Я слабо представляю, как туда вкрутить QtCore. Не говорю, что это невозможно, но не вижу смысла связываться.

За 6 лет работы с системой, написанной по принципу тонкий UI + кросс-платформенное ядро + небольшие велосипеды для недостающей системно-зависимой функциональности, я пришёл к выводу о целесообразности и удобстве такого подхода.
Про сложность понятно. Хоть и ИМХО вы не правы про инфраструктуру и сложность. Она довольно проста и логична. Я вообще считаю что Qt лучший на данный момент пример использования «классического» ООП.
А вот по поводу кроссплатформенности за пределами поддерживаемых систем можно подробнее? Ибо список систем довольно большой и мне интересно где вы не могли Qt использовать.
По поводу Андроида — использовать QtCore в нативной c++ библиотеке вроде не составляет проблемы. Особенно если вы отказываетесь от сигналов/слотов (тогда не надо организовывать Qt-очередь сообщений).
По поводу велосипедов — я принципиально не согласен. Они применимы только в одном случае — требования железа(производительность, ограниченность ресурсов и т.д.). Во всех остальных случаях они нежелательны в том числе по причине проблем с поддержкой. Смениться основной разработчик и будут проблемы.
Поддержу Вас.

Сложности могут возникнуть только при необходимости запустить кутешный eventloop, да и то решаемые, в остальном же QtCore такая же подключаемая библиотека как и любая другая, за одним исключением — это хорошо документированное, многофункциональное решение, а не сборная солянка, как тот же boost.

Насчет поддержки платформ — так в Qt есть слой архитектурной абстракции, нужно реализовать не так много компонентов, чтоб библиотека завелась на новой платформе (http://doc.qt.io/qt-5/qpa.html, http://doc.qt.io/qt-5/portingguide.html).
сложность самого фреймворка

Чегоооо? Вы же не серьезно, да?
Qt — это одна из нескольких больших библиотек в мире C++, которую можно начать использовать прям сразу, не вникая в дебри ее построения и мира плюсов вообще. Студенты без серьезного опыта плюсов осваивают либу без особых проблем. О какой сложности идет речь — прям реально любопытно!

вы теряете кросс-платформенность

Чееееееего? Мы вообще про Qt точно говорим?
Qt собирается почти под все девайсы, которые можно найти, включая всякие хитрые микроконтроллеры, отечественные Эльбрусы и прочие смесители от унитаза. Если нужно совсем что-то хитрое, берем близкий конфиг из папки mkspecs, правим его и собираем. Можно узнать, на какую платформу это сделать не получилось?

Я слабо представляю, как туда вкрутить QtCore.

Проинсталлировали вместе с приложением и профит, не?

небольшие велосипеды для недостающей системно-зависимой функциональности

Вы чуть выше писали про велосипеды с сетью и ФС. Это, мягко говоря, не могут быть «небольшие велосипеды», если только вы не делаете эхо-сервер.

P. S. Из всего перечисленного, Unicode-строки — единственное, для чего действительно сложно и нецелесообразно писать велосипед. Но есть другие, более доступные, чем Qt, 3rdparty-решения, которые можно включить себе в проект исходниками.
Для потоков есть std::thread, для файловой системы был велосипед, теперь жду filesystem в с++17. Слоты/сигналы — очень спорная функциональность, я бы не стал их где-либо за пределами UI и интерфейса ядра для связи с UI, даже если бы они были доступны. В ядре предпочитаю интерфейсы и коллбэки как более понятную и более контролируемую в compile-time связь.
То есть я правильно понимаю что единственная и главная причина это нежелание нести зависимости от библиотек?
А почему такие жесткие ограничения?
Не совсем так. Я максимально избегаю переизобретения любой нетривиальной функциональности, у нас куча сторонних библиотек в проекте. Но предпочитаю библиотеки, которые можно включить в свой проект исходниками (и сборку которых достаточно просто настроить).
libstdc++ от gcc 5.4.0 весит 1.5Mb, Qt5Core от Qt 5.8.0 весит 5.2Mb. Разница, конечно, в 3.5 раза, но назвать ее критической едва ли возможно. Особенно с учетом возможностей, которые Qt предоставляет. Многие embedded решения отказываются от libstdc++ в пользу Qt.

Использование своих велосипедов для работы с сетью вызывает улыбку. Либо у вас сеть только номинально, либо вы очень серьезные сетевики с крутым опытом, либо делаете что-то не то. Сеть в серьезном приложении очень часто является самым узким местом, и изобретать тут велосипеды вместо использования проверенных либ типа boost.asio — фундаментальная ошибка в архитектуре ПО.

с файловой системой у нас свои несложные классы-обёртки

Готов найти не менее трех проблем в ваших несложных обертках.

В итоге, у нас минимум зависимостей от сторонних библиотек

А в чем, собственно, профиты, кроме того, что можно написать «у нас минимум зависимостей от сторонних библиотек»? Какие-то проблемы написать «sudo apt install ...»?
Либо у вас сеть только номинально

Ровно в необходимом объёме. Сокеты, HTTP POST/GET без наворотов.

Готов найти не менее трех проблем в ваших несложных обертках.

Зачем? Всё, что нам нужно, работает на пяти ОС.

Какие-то проблемы написать «sudo apt install ...»?

Какой ещё sudo apt install на iOS?

А если https? Понятно, что можно все самим писать, но зачем?

Какой ещё sudo apt install на iOS?

Ну на целевую платформу все статически собирается. Речь про разработчиков.
Если https — проблемка, но в обозримом будущем эта проблема в нашем приложении не возникнет.

Ну на целевую платформу все статически собирается. Речь про разработчиков.

Интересная мысль, но в моём проекте вряд ли больше половины из уже имеющихся сторонних библиотек доступны через apt-get (а особенно — для кросс-компиляции под Андроид / iOS).
std::string path = root_path + '\' + fname;

Данная строка не скомпилируется, так как слэш экранирует кавычку. Исправьте пример пожалуйста (для новичков).
На самом деле не все так страшно с ОС. Для всего, кроме творений микрософт, есть POSIX. А вот для Windows и MS-DOS приходится делать отдельные ветки. Впрочем, в windows можно использовать какой-нибудь minGW, а на MS-DOS забить болт.
Да, программа, которая работает хотя бы на одной современной POSIX-совместимой системе относительно просто переносится на другие POSIX-совместимые системы. Но рынок диктует свои требования и отказаться от поддержки Windows зачастую невозможно.
А в нашем случае ситуация была еще сложнее — у нас были большие Windows-приложения и нам нужно было портировать их под POSIX. Огромный объем кодовой базы не позволял нам переписать все за раз — это был длительный итеративный процесс, параллельно с которым шло активное развитие этих продуктов. Как минимум из-за этого нельзя было «сжигать» мосты и переходить на POSIX, отказавшись от WinAPI (иначе на какой-то период сломалась бы сборка на MSVS и работа наших коллег бы встала).
MinGW не решает проблему — он использует WinAPI, ровно как MSVS (сейчас, кстати, мы перешли на него, отказавшись от MSVS). Вы, наверное, имели ввиду cygwin, в котором WinAPI завернут внутрь POSIX-совместимого API.
Разделитель лучше использовать так
boost::filesystem::path::preferred_separator
«Компилятор MSVS кодирует строковые константы в Windows-1251, а GCC — по умолчанию кодирует в UTF-8» — мне одному это утверждение показалось странным?
IMHO компилятор ничего не кодирует. Кодировка зависит от кодировки ОС, которая в Linux _обычно_ UTF-8, а в Windows (RU) в GUI-редакторах — CP1251.
Кодировка зависит от кодировки конкретного файла, в котором объявлена константа.

А как, интересно, задается кодировка для "конкретного файла"? Есть, конечно, Byte Order Marks, но это только для Unicode.

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

Например, если в коде есть такая строка, записаная в cp1251:
const char * str = "Какая-то строка";


А далее идет такой код:
std::locale::global(std::locale("C"));
std::cout << str << std::endl;


То выведется кракозябра.
Нет, в жизни это не так. Все компиляторы перекодируют «широкие» строки, а некоторые — даже «узкие». Чтобы убедиться в этом, можете взять MSVC 2010 и провести опыт: скомпилировать в ней один и тот же файл, закодированный в кодировки UTF-8, UTF-8+BOM и Win1251:

 #include <stdio.h>
int main()
{
   printf( "%hhu\n", static_cast<unsigned char>( 'я' ) );
   printf( "%hu\n", static_cast<unsigned short>( L'я' ) );
}


В случае с Win1251 вы получите ожидаемый результат, который никак не противоречит вашей гипотезе:
255 (это код символа 'я' в Win1251)
1103 (это код символа 'я' в UTF-16, которой представлен wchar_t на Win)

В случае UTF-8 вы получите:
143 (это один из двух байт UTF-8 представления символа 'я' — подходит под вашу гипотезу)
1057 (а это ошибка! компилятор неправильно закодировал L'я', так как неправильно воспринял исходник и сделал перекодировку win1251->utf16 вместо utf8->utf16)

В случае с UTF-8 с заголовком BOM мы имеем результат, идентичный первому варианту:
255
1103
И этот случай противоречит вашей гипотезе — компилятор представил «узкую» строку в 1251, несмотря на то что она была в исходнике в UTF-8.

Таким образом, не все компиляторы берут строки как есть из файла, они их иногда перекодируют.
У нас в деревне был случай.
Годиков X (а то и Y) назад Газпромбанк намутил себе iBank2.
Тогда еще ключи не на токенах, а в файлах.
Ну и вот пробуем с ним работать прямо из Linux (Fedora). С родной JVM не завелось, пришлось ставить Oracle Java for Linux.
И тут всплывают проблемы с кодировкой. Под Linux всё криво. Хотя Java же ж — «Make once — use anywhere» — правда?
А вот отнюдь.

В один из моментов разборок с техподдержкой (банка) порадовали две вещи:
1. «У вас неправильная Java, надо использовать IE и MS JVM и накатить исправление IE насчет MS JVM (это которое приводило MS JVM к „стандарту“ от Oracle)
2. И (это я на всю жизнь запомнил) — »Ваша Java не подходит нашему интернет банку". Моя. Oracle Java. Не подходит к газпробанковскому (точнее — бифит) приложению.

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

Но «ваша Java...» — это среди меня теперь мэм.
Хотя Java же ж — «Make once — use anywhere» — правда?
Нет.

«У вас неправильная Java, надо использовать IE и MS JVM и накатить исправление IE насчет MS JVM (это которое приводило MS JVM к „стандарту“ от Oracle)
Во-первых в те времена Oracle никаких «стандартов Java» ещё не создавал, а во-вторых MS Java — была целенаправленно сделана несовместимой с версий от Sun'а.

И (это я на всю жизнь запомнил) — »Ваша Java не подходит нашему интернет банку". Моя. Oracle Java. Не подходит к газпробанковскому (точнее — бифит) приложению.
Думаю что Java у вас была не от Oracla и даже не от Sun'а. Скорее всего это была Blackdown Java — и да она была абсолютно несовместимой с MS Java'ой, причём это не было ошибкой: это была цель, которой Microsoft хотел добиться сознательно.

После того, как им суд погрозил пальчиком они забрали «свои игрушки» и сделали .NET и C#.
В данном цикле статей я расскажу, как мы сделали свои продукты настоящими кроссплатформенными приложениями; как заставили их работать на Linux, MacOS и даже под iOS и Android


Отлично. Но где можно посмотреть эти самые продукты? На сайте https://sbis.ru/download нет ни малейшего упоминания о «кроссплатформенности».
Мобильные приложения СБИС сделаны на нашей платформе

https://play.google.com/store/apps/details?id=ru.tensor.sbis.droid

https://itunes.apple.com/ru/app/%D1%81%D0%B1%D0%B8%D1%81/id1156518720

Остальное — облачные решения;
Облако sbis.ru построено на платформе
И снова увидел по ссылкам Andoid, iOS и web, какое это отношение имеет к Linux и Windows?

Т.е. по сути и статьи и вашего ответа решений под Linux нет?
Весь backend облачных решений живет на Linux и основан на платформе
Извините, смотрю с той стороны, которая доступна простому пользователю. И простому пользователю не Windows из перечисленного ничего не доступно. Даже облачная часть sbis требует ActiveX для подписи и шифрования и как следствие без IE не имеет никакого значения.

Облачный СБИС работает не только в IE. И подпись и шифрование работают у нас и в Chrome, и в FireFox.

Мда?.. Ключевое — «у нас»: вот у нас не так всё хорошо.
(Fedora 25, Chromium, если что)
На скрине — Linux. Я нигде ничего не писал про Linux и криптографцию. Но, к слову, работы в этом направлении ведутся. СБИС Плагин (который и занимается этими всеми вещами по команде из браузера) сейчас переводят на C++ что позволит запустить его и на Linux. На эту тему будет отдельная статься.
Простите, я пишу
И простому пользователю не Windows из перечисленного ничего не доступно.


и ваш комментарий:
Облачный СБИС работает не только в IE. И подпись и шифрование работают у нас и в Chrome, и в FireFox.


Разговор слепого с немым?

Кажется, я не заметил "не" в "не Windows"...

А что — Android это у нас уже Windows? Или iOS?
А они уже в числе десктопов, можно уже бухгалтерш за них усаживать?
Подход к строкам описанный @ensor_sbis использовался у нас в конторе, по энерции, довольно долго, но потом я перевел все проекты на UTF-8 и очень рад этому. Основные недостатки старого подхода, на мой взгляд, такие:

1. У автора статьи сказано, что в wchat_t помещается Unicode символ (я так понимаю подразумевается UTF-32), но на самом деле, целиком умещается только code point, а символ, по прежнему, может кодироваться несколькими code point-ами.
2. В случае сериализации, особенно в рамках ASCII <= 127 получается жуткий перерасход по памяти.
3. В случае сериализации появляется понятие byte order внутри code point-a. Следовательно имеем неразбериху и дополнительные накладные расходы на обработку строк.
4. В рамках исключений С++, даже если очень нужно, невозможно передать локализованной сообщение, так как нет перегрузки для wchar_t.

Преимущества UTF-8:
1. Компактно, при сериализации и по памяти.
2. Нет проблем с порядком байт, можно сразу читать из потока или файла.
3. Парсеры и форматтеры пишутся точно также как и для всех «узких» строк, на практике можно вообще не обращать внимание что строки в UTF8.
4. Удобно смотреть дампы пакетов и памяти, так как, опять же, нет вариантов с порядком байт.
5. И последние, это уже вкусовщина, но мне, лично, удобней и приятней видеть в коде просто кавычки вместо L"..." или L'...'
А у нас компанийский стандарт: UTF-8 для передачи, обработки и хранения, UCS-2 для отображения и пользовательского ввода. Ибо накладные расходы процессорного времени при пользовательском вводе в UTF-8 (особенно, если с автодополнением, и в произвольное место) сильнее сказываются на субъективной производительности, чем дополнительный расход памяти.
Странно. У меня скорость даже выросла, так как работа со стоками UTF-8 (если это конечно не текстовый процессор), обычно, происходит последовательно и в этом случае она ничем не отличается от работы с простым ASCII.
При вводе нужна постоянная трансформация из code point в позицию в строке и обратно (для показа выделения и позиции ввода). Если индекс в строке соответствует code point — это быстро. Если нет — либо медленно, либо нужен дополнительный кеш позиции, с нетривиальным алгоритмом обновления при автокомплите. На настольных устройствах всё круто. На мобильных можно заметить снижение FPS при работе с большими строками. Ситуация осложняется разными способами получения результатов ввода на разных платформах.
При вводе нужна постоянная трансформация из code point в позицию в строке и обратно (для показа выделения и позиции ввода).
Вы это серьёзно? Как у вас с поддержкой вещей типа а҃? Если же у вас установка, что «в природе существует только русский и английский» — то зачем вообще заморачиваться с Юникодом?

Если нет — либо медленно, либо нужен дополнительный кеш позиции, с нетривиальным алгоритмом обновления при автокомплите.
Он, собственно, нужен всегда, когда вы хотите работать с Юникодом.
У нас кроме русского и английского практически все европейские языки. Поддержка арабских, азиатских и тому подобных, каюсь, не планировалась. А вся европейская диакретика есть в BMP в виде монолитных символов, к которым можно привести строку в ходе нормализации.

Конечно, круто делать полную поддержку юникода, с составной диакретикой и поддержкой всех планов, но это далеко не всегда нужно для того, чтобы приложение работало. Это вопрос баланса между желаемой технической крутостью, которую котят разработчики, и минимальным сроком разработки с минимальными затратами, как хотят манагеры.
Есть такой бородатый сайт про UTF-8, проще на него ссылку кидать, чем каждый раз писать про преимущества UTF-8. :) И по-хорошему надо всегда использовать только ее для всех внутренних представлений, а если очень необходимо снаружи библиотеки иметь другую кодировку, конвертировать в нее по требованию.

После заявления что в C++11 нет функционала для работы с сеть задумался, а стоит ли продолжать читать)

Вопрос «что, где и как должно быть реализовано» — он, на самом деле, чрезвычайно непрост.

То есть понятно, что как бы «работа с сетью» — это, наверное, не есть «базовая функциональность языка программирования»… с одной стороны. А с другой — работа с перфокартами входила в ISA IBM 360, где, вроде как, им тоже не совсем место, да?

Так что не стоит уж прям так сразу «сплеча» рубить…

Я конечно понимаю что грань между тем что называется стандарт языка и стандартная библиотеки языка очень зыбкая, но она всё-таки присутствует. К тому же это не одно спорное заявление в статье. Следом идёт про то что реализация HTTP запроса делает код на С++ не кроссплатформенным. А я например знаю, как реализовать это кросплатформенно. Правда это будет иметь "фатальный недостаток")

А я например знаю, как реализовать это кросплатформенно.
Оставаясь в рамках C++11 и не используя не-кроссплатформенные API? Хотел бы я на это посмотреть!
Нет конечно, используя сторонние библиотеки, я же написал что будет иметь «фатальный недостаток»)
Ну а что вам мешало пойти тем же путем? Впрочем вы с таким восторгом рассказываете о своей платформе, поэтому наверно не стоит даже начинать про «зачем писать свой велосипед?»)
Вы не видите разницы между сторонними библиотеками и тем, что предоставляет чистый C++11?
Нет в одиннадцатых плюсах ни поддержки сети, ни поддержки файловой системы. И тут почти всегда выруливает буст.
Вы точно на мой пост ответили?)
Я прекрасно вижу разницу между сторонними библиотеками и стандартной библиотекой С++. Или вы что-то другое имели ввиду во фразе «чистый C++11».
Кстати С++11 это номер обновления версии стандарта на язык С++, а не что-то отдельное и самодостаточное. Кстати есть уже и С++14, и даже С++17 — работы с сетью в них тоже нет, и думаю не будет никогда. В философии С++ есть фишка — не тащить прикладной код в стандартную библиотеку.
есть возможность написания строковых констант на русском языке в коде

Второе требование в случае UTF-8 не выполняется, к примеру, в MSVC 2010, где строковые константы кодируются в Windows-1251.

Мне кажется, Вы здесь вводите в заблуждение читателей. Строковые константы в UTF-8 прекрасно работают в MSVC 2010. Вам просто нужно превсести все ваши *.h и *.cpp файлы в UTF-8 без BOM и забыть о проблеме с кодировками. Ну и настроить среду так, чтобы новые исходники автоматом создавались в UTF-8.

Кроме этого, если вы реально планируете активно работать с многоязычными текстами, то, на мой взгляд, следовало сразу отказаться от вашего первого требования:
фиксированная ширина символов — возможен произвольный доступ к символу по его индексу

Из-за него вы перешли на UTF-32, а это большой оверхед. При том, что доступ к символам по их индексам на практике — не такая уж и частая задача. Большинство задач, связанных со строками, можно свести к их обходу с помощью итераторов.

Нет, это не так: https://msdn.microsoft.com/en-us/library/mt708821.aspx
By default, Visual Studio detects a byte-order mark to determine if the source file is in an encoded Unicode format, for example, UTF-16 or UTF-8. If no byte-order mark is found, it assumes the source file is encoded using the current user code page


MSVS кодирует «узкие» строки в кодировку локали: https://msdn.microsoft.com/en-us/library/mt589696.aspx
The execution character set has a locale-specific representation.


Таким образом, в случае, если студия компилирует файл в UTF-8, она воспринимает его как файл в кодировке локали. Так как она кодирует узкие строки тоже в кодировку локали, преобразование как таковое не требуется => все ваши UTF-8 строки попадают в исходном виде. Но все это здорово работает, пока в файле не встретится код, не существующий в кодировке локали (это 0x98 в случае русскоязычной локали, где кодировка Win1251).

Кроме того при сборке в MSVS исходников в UTF-8 появляются проблемы с широкими строками — MSVS воспринимает файл как 1251 и выполняет перекодировку Win1251 -> UTF-16 вместо UTF-8 -> UTF-16 и получаем «кракозябры»

Кроме этого, если вы реально планируете активно работать с многоязычными текстами, то, на мой взгляд, следовало сразу отказаться от вашего первого требования:
фиксированная ширина символов — возможен произвольный доступ к символу по его индексу

В статье писалось об этом, но повторюсь — у нас была огромная кодовая база (десятки миллионов строк кода), в этом коде были завязки на фиксированную ширину символов. В принципе переписать этот код — очень тяжелая задача. Но кроме этого, как уже многократно писалось, шло активное развитие продуктов и нужно было портировать таким образом, чтобы не блокировать работу других разработчиков (нельзя было развалить сборку на недельку год, пока переводим на UTF-8).
Мы пошли путем microsoft'а — все строки завернули в макрос _T( «строка» ), строковым функциям и типам сделали псевдонимы (наподобие _tcscmp). Благодаря этому мы могли жить, поддерживая сразу два варианта сборки: сборка на узких строках (из которой выпускались все production решения) и сборка на широких строках (которая итерационно развивалась в течение года). В случае, если бы мы стали использовать UTF-8, мы не смогли бы обеспечить такую совместимость.
Нет, это не так: https://msdn.microsoft.com/en-us/library/mt708821.aspx

Вы даёте ссылку на документацию к VC 2015, а тут вроде бы речь идёт про 2010. Если бы речь шла про 2015, то проблемы вообще бы не было, просто потому, что у компилятора есть соответствующая опция /utf-8, ссылку на которую Вы и даёте.

MSVS кодирует «узкие» строки в кодировку локали: https://msdn.microsoft.com/en-us/library/mt589696.aspx.


Там же написано следующее

The basic execution character set and the basic execution wide-character set consist of all the characters in the basic source character set...


Ну а про basic source character set сказано так

When source files are saved by using a locale-specific codepage or a Unicode codepage, Visual C++ allows you to use any of the characters of that code page in your source code

Т.е. Microsoft явно разрешает использовать все символы юникода в исходниках.

Вы не подумаете, что я сильно придираюсь, просто хочу понять, есть ли проблема на самом деле и как её воспроизвести. Собрал только что тестовый консольный проект в VC2010, сохранил исходники в utf-8, создал в коде узкую строку на традиционном китайском языке и никаких проблем с ней не обнаружил.
  const char* TestString = "測試";
  printf("%d", strlen(TestString) );

Этот код у меня на экран консоли выдаёт цифру 6
Как минимум с широкими строками проблемы точно будут:

#include <windows.h>

int main()
{
    MessageBoxW(NULL, L"Тест", L"Тест", MB_OK);
}


Результат:

image
  const char* TestString = "測試";
  printf("%d", strlen(TestString) );

Кстати говоря, в вашем коде есть неопределенное поведение :) Функция strlen возвращает тип size_t, а формат указан для int. По стандарту это UB:
… If any argument is not the correct type for the corresponding conversion specification, the behavior is undefined.

Для size_t надо использовать %z
Для старых студий вообще даже issue на багтрекере есть:
https://connect.microsoft.com/VisualStudio/feedback/details/341454/compile-error-with-source-file-containing-utf8-strings-in-cjk-system-locale

В этом issue люди словили проблемы из-за того что у них в исходнике встретился код, не входящий в кодировку их локали (о чём я писал выше)
Sign up to leave a comment.