Pull to refresh

Comments 90

«C++ набрал серьёзную популярность в 2015» звучит неправдоподобно. Даже если он действительно таки набрал, а не растерял популярность, это единицы процентов по отношению к той популярности, которую он набрал за предыдущие десятилетия.

Tiobe это мусорный рейтинг, в котором Go был на 49 месте (а сейчас выпал из 50, ха-ха-ха)
TIOBE — вполне себе рейтинг. Разве есть что-то лучше?

Просто погрешность, с которой происходят измерения, довольно велика, и поэтому дальше первой десятки можно не смотреть.
Он составляется на основе поисковых запросов, если меня память не подводит. Более-менее показывает, сколько НОВИЧКОВ начинает пользоваться языком (не очень могу представить, чтобы я начал гуглить «C++ how to remove object from vector», у меня сомнения что запросы вроде «std vector emplace_back» попадут в статистику по языку.

«разве есть что лучше» — ну «чуть лучше» я бы назвал статистику по резюме/вакансиям с упоминанием этого языка.
«Композитные» рейтинги популярности не работают, имхо. Надо смотреть более конкретные метрики. Кол-во вакансий на hh. Кол-во вопросов (или, например, только новых вопросов) на stackoverflow. Кол-во проектов на github. И т. д.

По Tiobe С в 6-7 раз популярнее JavaScript. При всей моей нелюбви к последнему, это не погрешность, это бред.
Как составить рейтинг рейтингов?

Открыть рейтинг, посмотреть на каком месте какой-нибудь недоязык, убедиться, что не на первом, закрыть рейтинг.

Спасибо за обзор.
Все-таки думаю что у С++ очень неплохие перспективы в свете падения темпов роста производительности процессоров.
Поскольку язык становится богаче, современнеее (но в то же время и проще)

Не заметил упрощения…
Ну сравните проход по std::map раньше и теперь.
Было:

typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = myMap.begin(); iterator != myMap.end(); iterator++) 
{
    // do something
}


стало:

for (auto& k : myMap) 
{
    // do something
}


Заметили упрощения?
Согласен, писать стало проще, а вот понимать теперь нужно уметь больше, старый способ же не исчез из языка.
Не важно сколько фич ты используешь когда пишешь свой код, в реальном мире понимать чужой все равно необходимо. В этом плане, имхо, сложнее всего Scala, но C++ не сильно отстает.
С++ — довольно прост для понимания для любого, кто знает этот язык. Почему-то расхоже мнение, что в нём большое количество сложных конструкций, но это не так. C++ сложно читать только если вы не знаете C++, а это характерно для многих языков.
Рискну осторожно предположить, что Бьерни знает…
Ну… он давал оценку своим знаниям, примерно, как 7 из 10. Честно скажу, не помню точно где я это видел, так что прошу поправить если сильно ошибся.
Нет, я смутно-смутно что-то такое помню, поэтому и сказал «осторожно».
Александреску наверное…
Господа минусующие, можно пример кода на С++ в котором сложно разобраться? Не холивара ради, просто хочется понять — может быть, я просто слишком давно пишу на плюсах и у меня действительно «глаз замылился»?
UFO just landed and posted this here
Просто случайная строчка кода из самой популярной библиотеки.
Bind, далеко не самая страшная вещь в бусте.

И да, это сложно, про простые вещи не пишут статей в духе «Давайте рассмотрим как заимплеменчена эта концепция через синтаксисе с++».
Причём здесь язык-то? Нафигачить однобуквенных аргументов можно в любом языке. Давайте быть объективными, такие строчки бывают в любых языках программирования. Внутри библиотек на джаве и питоне ещё и не такое встречается, не говоря уже про скалу. Однако, эти языки почему-то не считаются сложными. Что я упускаю?

Синтаксис С++ громоздкий, с этим никто не спорит, но он не сложнее для понимания большинства других.
Сложными для чтения, конечно же
UFO just landed and posted this here
С++ — довольно прост для понимания для любого, кто знает этот язык.

Это фраза ни о чем. Человек говорит, что чем больше конструкций в языке (втч упрощающих жизнь), тем язык сложнее, потому что надо знать уже n+1 конструкцию для чтения кода. Вы парируете «кто знает язык, тот знает язык».
Например — я очень редко пишу что-то на С++, при этом конструкция
typedef std::map<std::string, std::map<std::string, std::string>>::iterator it_type;
for(it_type iterator = myMap.begin(); iterator != myMap.end(); iterator++) 
{
    // do something
}

нереально громоздка, но понятна любому, кто знает что-то о шаблонах (базовом элементе языка, которому 100 лет в обед).

Конструкция
for(auto it_type iterator = myMap.begin(); iterator != myMap.end(); iterator++) 
{
    // do something
}

И проста и понятна, в том числе для тех, у кого ++ — не основной язык, потому что механика спецификатора auto прозрачна.
А вот запись
for (auto& k : myMap) 
{
    // do something
}

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

Проще для написания.
Сложнее для понимания.
Я согласен с вами, но ведь аналогичные конструкции есть и в других языках, например в джаве, которой никто не предъявляет сложность. Моя фраза относилась к части
В этом плане, имхо, сложнее всего Scala, но C++ не сильно отстает.
С тем, что язык становится сложнее спорить тяжело.
UFO just landed and posted this here
Даже для понимания проще, если знать, что такое auto и как выводятся типы у шаблонов (а в C++ это знать всё равно надо).

И об этом — второй предложенный мною вариант, а не 3й.

Кроме того, range-based for loop сразу чётко даёт понять намерение кода чуть лучше, чем старый-добрый for loop

Вы не поняли основную мысль.
Разговор шел о том, что чем больше разнообразие конструкций, тем язык сложнее. Только и всего. Шаблонам — 100 лет в обед, их все знают. auto интуитивно понятен, именно поэтому второй варинат читается легко — это комбинация интуитивно понятного и старого, всем известного. А вот range синтаксис уже китайская грамота. При том, что это удобная вещь.

UFO just landed and posted this here
Человек изначально написал «Согласен, писать стало проще, а вот понимать теперь нужно уметь больше, старый способ же не исчез из языка», так что контекст очевиден.
Вообще если смотреть рейтиги TIOBE видно что рейтинг языка низок как никогда (хотя и правда сейчас на 3 месте)

www.tiobe.com/index.php/content/paperinfo/tpci/C__.html

А вообще уже 2016 год, а я знаю кучу компаний (наверное большинство) которые даже С++11 не используют (и значит им все это не надо — что кстати тоже не плохо — кого то устраивает то что есть)

А те кто следят за новинками языка и кому это действительно важно — те будут использовать, например Rust. Конечно остаются проблемы поддержки legacy code, но как раз для этого не так уж и важен новый стандарт.
Я пытался предложить улучшения в области метапрограммирования — разрешить передавать в шаблоны не только типы и целочисленные константы, но и любые другие compile-time конструкции (включая float-константы, строки и даже произвольные корректные фрагменты кода)
К сожалению, народ на isocpp.org не поддержал.
А можно ваш proposal глянуть почитать? Особенно интересна motivation часть, конечно.
Лично я вижу в предложении NeoCode, как минимум, унификацию ибо текущие ограничения в большинстве своём не понятны и избыточны, а также явную возможность избавления от макросов для генерации кода много где, отдав эту функциональность шаблонам.
Я в основном и имел в виду унификацию. Что касается мотивации, то я особо не расписывал, т.к. реальные примеры где это нужно достаточно сложные и их сложно объяснить вне контекста реальных проектов. Но на этом и рефлексию можно сделать, и кодогенерацию, и много чего еще.
Рефлексию я не представляю, как можно через это сделать, интересно стало, можете с потолка пример как это может работать?
UFO just landed and posted this here
UFO just landed and posted this here
Осталось добавить Garbage Collector и будет ещё одна Java/.NET вирт машина.
Кстати .NET умеет собирать в нативный код (уже), т.е. работает как приложение написанное на C++.
https://msdn.microsoft.com/en-us/vstudio/dotnetnative.aspx
Я либо вас не понял, либо вы неправы просто-таки фундаментально.
Я имел в виду, что в C++ появляются постепенно сахар, который уже давно есть в C# и возможно придут к Garbage Collector со временем.
А тем временем C#/.NET идет на встречу C++ — ускоряя загрузку приложения, уменьшая потребление памяти.
Мне представляется, что вероятность появления GC в С++ крайне мала, а вот опциональный ARC как в Objective-C может когда-нибудь и будет.
Задача та же, но решает принципиально хуже в первую очередь потому, что писать каждый раз конструкцию уменьшающую читабельность как-то вообще не камильфо. Тут дело в другом, это решение более гибкое — если проекту нужна максимальная скорость работы, то есть возможность вообще отказаться от использования умных указателей, или применять их ограничено. Если скорость не так критична, и умные указатели используются повсеместно — то глобально включенный ARC будет эквивалентен и избавит лишних движений.

std::shared_ptr<SomeType> someName = std::make_shared<SomeType>(constructor, parameters, here);

vs

SomeType *someName = new SomeType(constructor, parameters, here);

SomeType *someName = new SomeType(constructor, parameters, here);
auto someName = std::make_shared(constructor, parameters, here);
разница в 10 символов или 13%.
Для максимальной скорости выделения памяти обычно пулы используют, либо что-то вроде placement new.
  • Во-первых, где в этой строчке тип указывается хоть один раз? Мне кажется что-то пропущено.
  • Во-вторых, auto не везде разумно/возможно вставлять, в объявлении полей класса или параметров методов, их возвращаемого значения все равно нужно прописывать типы явно, так что читабельность все равно падает по сравнению с голыми указателями, число символов возрастает.
  • В третьих несколько вариантов написания одного и того же явно избыточны, каждый будет писать как придется, опять вспоминаем про увеличивающуюся фрагментацию.
Насчёт конструкции, уменьшающей читабельность — спорно. Многие могут вам сказать, что явное указание, что переменная является умным указателем, повышает читабельность, ведь программисту не надо гадать, умные указатели используются в этом конкретном проекте или нет.
Насчёт пункта 3 — с этим приходится мириться, потому как ломать обратную совместимость никто не будет.
Если мы все еще говорим об ARC, то это определяется глобально в настойках проекта, и все указатели становятся умными, гадать не нужно.
Да о том и речь, что просто посмотрев на кусочек кода/файл (например, нагуглив) нельзя точно сказать, включён он или нет.
во-первых, я не посмотрел предпросмотр, и хабрапарсер зохавал шаблон. Разница в 13% в пользу new, естественно.
про авто — согласен, его только в таких очевидных примерах, где тип явно виден, удобно использовать (или для лямбд).
3) — тут не поспоришь.
Дополню mapron поскольку использовать new и delete не безопасно, впрочем как и сырые указатели, а с C++14 это окончательно пофикшено и в общем случае следует использовать unique_ptr вместе с make_unique так что разница в написании вообще нулевая.

P.S. на всякий случай напоминаю всем разработчикам на C++, что unique_ptr+make_unique фактически является синтаксическим сахаром и не привносит дополнительных накладных расходов при сравнении с сырыми указателями и использованием new+delete, однако его использование гораздо более безопасно из-за особенностей генерируемого кода, впрочем как и из-за отсутствия необходимости явного вызова delete, в котором помимо явной утечки в случае exception перед ним можно ещё ошибиться из-за [] в случае массива (неважно при каких условиях, факт в том, что можно). Ошибку же с использованием new+delete можно отловить только при анализе утечек памяти при завершении работы приложения в рантайме либо грубые ошибки (массив — единичный элемент в случае delete) некоторыми статическими анализаторами.

P.P.S. я понимаю о чём вы говорите и что можно сделать синтаксис проще, но для этого, учитывая концепцию C++ надо будет однозначно вводить специальную директиву, отключающую обратную совместимость и это касается не только new, но и многого другого из «наследия прошлого». Наверняка после введения модулей такую директиву сделают, чтобы в пределах модуля использовать канонический C++ с обратной совместимостью, а вне его пределов уже современную на тот момент версию языка. Но это пока только мысли на будущее ибо требует очень большой работы от разработчиков компиляторов, а пока уж как есть ибо и так изменений огромное количество и для авторов компиляторов и для разработчиков на языке.
поскольку использовать new и delete не безопасно, впрочем как и сырые указатели
Ну вы нашли, чем плюсовика напугать:
«Си — инструмент, острый, как бритва: с его помощью можно создать и элегантную программу, и кровавое месиво» Брайан Керниган
Если серьезно, то нулевая разница только по сравнению с shared_ptr, пример же приведен для сравнения с ARC, и unique_ptr тут картину не улучшает. Но в целом замечание ценное, спасибо.
Ну вы нашли, чем плюсовика напугать

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

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

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

P.P.S. у меня ещё просто профориентация на проекты, которые должны очень долго работать и быть максимально надёжны, так что некоторая паранойя в этой области тоже есть, не скрою :) Вообще мне для заверения треда уж очень хочется пригласить к обсуждению Andrey2008 ибо он как один из разработчиков хорошего (по моему опыту) статического анализатора, наверняка, может ткнуть в годные примеры, где в известных и используемых многими проектах использование new/delete, включая ошибки с оператором [], да ещё и голое их использование без обвёртки без соблюдения принципа RAII приводило к утечкам, порчи памяти и другим «радостям».
Да, вот и я не знаю как побороть проблему на корню. С auto_ptr всё уже давно понятно, благо он deprecated с C++11, а с C++17 вообще будет удалён.
`auto_ptr` не умный, а так себе указатель.
UFO just landed and posted this here
В функции unique_ptr можно ведь и ссылкой передавать. Для shared_ptr есть ещё weak_ptr без передачи владения.

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

Пожалуй самое главное замечание на счёт умных и сырых указателей: не стоит мешать их вместе для одного объекта ибо этим можно создать себе дополнительные и особенно экзотические проблемы.
UFO just landed and posted this here
Да, вы правы. С меньшей универсальностью полностью согласен. Также и с тем, что самое опасное это явные new и delete.
При помощи лёгкого макроса и маленькой шаблонной функции можно превратить это
std::shared_ptr<SomeType> someName = std::make_shared<SomeType>(constructor, parameters, here);

в это

auto someName = share new SomeType(constructor, parameters, here);
Кстати .NET умеет собирать в нативный код (уже)

Подобные попытки предпринимались неоднократно и многими. Особенно на ранних стадиях развития виртуальных сред исполнения. Вот только один пример для Java среды: https://gcc.gnu.org/java/
Однако приоритет развития был всё-таки отдан «компиляции на лету» (англ. Just-in-time (JIT) compilation).
Это не попытка, это готовый продукт. Использовать или нет решайте сами.
Да нy нету? C++/CLI для любителей GC.
Там для GC свой тип ссылок и указателей и свой оператор new. managed c++ это редкий уродец с каким то зашкаливающим количеством возможных ссылок на обьекты, сделанный как мне видится, исключительно для написания производительных биндингов в .Net с сабжа и сишечки.

А, да, там ещё два типа шаблонов, с интересными правилами взаимопременения :)

Вообщем использовать эту штуку для чего то кроме клея, не приведи ни одному любителю GC как говорится.
Боюсь показаться ретроградом в треде про С++17, но господа, не слишком ли много мы получили? Если раньше разговоры про то, что никто не знает С++ полностью были шутками, то теперь это реальная ситуация. Других языков, которые бы так быстро и решительно насыщали фичами я не знаю. В итоге мы оказываемся в ситуации, когда каждый знает и/или использует какое-то свое подмножество, из-за чего язык перестает быть универсальным, разбираться в чужом коде становится гораздо сложнее. И это я еще молчу о злоупотреблении фичами из серии «потому что могу» и «эту я еще не пробовал».
Не думаю. Новые стандарты сейчас вообще мало где используют, а как только станут использовать все сразу во всём разберутся (из тех кто реально пишет на плюсах). Там не так уж много нововведений и они совсем не сложные. А насчёт использования подмножества языка — сейчас картина точно такая же, к сожалению.
UFO just landed and posted this here
Проблема в том что C++ спал летаргическим сном с 1998 года до C++2011, в то время как остальные языки постоянно насыщялись удобными фичами. Поэтому теперь приходится наверстывать.
И появились вещи типа Qt (где написали свои библиотеки для всего и оно теперь как-то должно существовать параллельно с этими С++1Х, а Qt используют многие)
UFO just landed and posted this here
Идеального нет, но в целом для работы с Qt требуется очень небольшое и прозрачное подмножество языка без магии и неоднозначностей, сигналы-слоты опускают порог вхождения даже в многопоточное программирование, из-за чего С++03 подтягивается до уровня современного языка. Это я не говорю о средствах работы с сетью, файловой системой, и т.д. что в официальном стандарте только в планах.
UFO just landed and posted this here
то теперь это реальная ситуация

Да, это уж точно — я преимущественно на C# специализируюсь, и поддерживать знание C++ "в фоне" становится все сложнее и сложнее. Благо моя сфера интересов, связанная с C++, в основном Qt\QML касается, а там более или менее свои законы и устоявшиеся идеологии.
Других языков, которые бы так быстро и решительно насыщали фичами я не знаю.

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

Жаль что убрали.
Ну так можно перегрузить оператор new внутри класса, и так же выделять память.
UFO just landed and posted this here
А compile-time интроспекцию так и не сделали. Придется по-старинке лютым копипастом сериализацию/десериализацию делать.
Даа уж, у меня в подобных особо тяжёлых случаях частенько вообще кодогенерация на макросах #жизнь-боооль.

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

Когда активно участвовал в проекте FlylinkDC++ то масштабно занимался рефакторингом, в т.ч. гуйной части и там для унификации менюшек и много чего ещё это было нужно, даже вопрос на тостере тогда задал, благо что конкретно в этом случае у Visual Studio оказался специальная конструкция __if_exists благодаря которой в этом случае удалось всё унифицировать «малой кровью».
Для вашей задачи можно сделать что-то вроде

eval_if(b,
  [&]() { t->doA(); },
  [&]() { t->doB(); }
);

где b — constexpr boolean выражение
Кстати, у меня такое чувство что предлагаемый «оператор точка» это что-то очень близкое к «свойствам» (properties), которые есть во многих языках. Только более общее: если свойства определяют геттеры и сеттеры для полей класса, то «точка» — геттер и сеттер (одновременно? или можно развести их через const?) для всего объекта класса сразу.
плюс ещё проще писать паттерн прокси
Таки не «корутины», а сопрограммы. :) Термин прижился в русском языке много лет назад. :)
Еще было бы интересно иметь в языке возможность присваивать классам и функциям произвольные атрибуты, чтобы они наследовались порожденными классами и вызываемыми функциями), и задавать правила соответствия атрибутов объектов класса и работающих с ними функций.

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

Например, как вы это видите?
В простейшем случае — примерно так:

// Функция, вызываемая на известном уровне приоритета

F1 (...) _attrval (Level = 2) {… }

// Функция, вызов которой допустим только на определенных уровнях приоритета

F2 (...) _attrcond (Level <= 1) {… }

Значение атрибута Level, заданное для F1, распространяется на все функции, явно вызываемые из нее. Если на этом пути вдруг встретится вызов F2 — у компилятора будет возможность выдать предупреждение, и не потребуется писать тесты для всех возможных путей вызова F2.

То же самое можно сделать, например, для функции, делающей проход по списку в предположении, что блокировка, защищающая список, в данный момент захвачена текущим потоком. Тут уже нужно будет присвоить один атрибут классу (или конкретному объекту) списка, а другой — функции, которая с ним работает.

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

Смысл в этом примерно тот же, что и у константных объектов/методов, только в дополнение к константности вводятся дополнительные атрибуты объекта/функции.
Блин, как же я мечтаю о том, чтобы C++ с каждым стандартом всё больше и больше приближался к D, пока в один благословенный день оригинальный код D вдруг не стал собираться C++ компиляторами.
Как раз сейчас происходит мощная передача концепций обратно — из D, где они были опробованы, в C++-17. Навскидку — модули, ранги (ranges) и много другого, в материалах CppCon-2015 очень много таких примеров.
Полного слияния однако совершенно точно не будет, и это хорошо, зато появятся мощные инструменты для экспорта кода, перекрестному использованию библиотек, и т.д.
Предсказываю появления вместо диады C/C++ мощной триады C/C++/D и приветствую ее приход.
Как мне кажется, главная проблема D в том, что у него, в отличии от C++ нет ниши.
Sign up to leave a comment.