Pull to refresh
35
0
Владимир Быко-Янко @BykoIanko

User

Send message

Спасибо! Интересный документ.

Спасибо за комментарии!

Хочу кое что уточнить. То что я писал выше относится к стандарту C++17. В C++20 приняли "two's complement". Это раздел 6.8.1, параграф 3. То есть код из начала статьи:

uint32_t width = 7;
int32_t signed_offset = -width;

должен всегда работать одинаково и signed_offset в C++20 должно быть -7, как я понимаю.

Спасибо огромное! Поправил.

Да и проще написать int32_t signed_offset = -(int32_t)width;

Ага. Как вариант.

Нет там никакого переполнения. Просто одни и те же биты интерпретируются по-разному.

@screwer Уточните п-та, какой параграф стандарта С++ гарантирует интерпретацию битов по разному в случае знаковых типов? Ссылку на драфт я привел в конце статьи.

Очень рекомендую почитать Hacker Delight, чтобы не делать подобных "открытий".

Спасибо, обязательно почитаю!

Как будто c variadic functions должно работать. Я к тому, что еще до вызова variadic functions можно прикинуть сколько места нужно для возвращаемого значения.

А в чем сомнения по поводу __stdcall?

Спасибо за ответ и за комментарий! Я посмотрю патч и внимательнее прочитаю предложение Антона. Интересно.

Быть может, я упускаю из вида, какие-то особые платформы, но кажется, что уже есть целый ряд случаев, когда любой современный компилятор сделает NRVO. Надеюсь на предложение Антона обратят внимание...

Сейчас ни один компилятор не поддерживает все описанные в paper кейсы. Я отправлял патч в Clang, чтобы покрыть на 20% больше кейсов, чем поддерживается сейчас, но до конца не добил тему, потому что патчи медленно принимаются.

А что за возражения? По делу или просто не обращают внимание на патч?

Спасибо за уточнение.

Думаю, в одной функции может быть, чтоб иногда было RVO, иногда NRVO, а иногда было вызвано копирование. Т.е. если говорить языком стандарта, то и RVO, и NRVO это частные случаи отмены копирования (copy elision). Крайняя точка принятия решения о том, случится ли отмена копирования - это точка вызова ф-ции в Run Time. Технически даже можно представить, что в ряде ситуаций, компилятор может оставить место под результат работы функции на стеке и начать ее исполнять. И уже позже, создать в оставленном месте результат работы функции. А если так не будет получатся, то по возможности выполнить перемещение в оставленное место. А если и это не возможно, то копирование.

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

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

Да, это отличный подход! Много таких штук в C++, которые не понятно сработают или нет.

Вижу мне уже вроде намекают, что такие атрибуты есть. Не знаю, я вообще на C++-сник уже давно.

Если не сложно, уточните п-та, о чем речь. Мне про них не известно, а если есть я бы хотел знать. Если информация не очень точная, можно и в личку. Спасибо!

некоторой популярностью бы пользовался атрибут "выдавать ошибку, если в данном месте не удается применить copy elision".

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

Мы утонем в атрибутах с таким подходом.

Да. Есть такое дело :)

Ведь уже появился синтаксис атрибутов, что мешает наконец завести атрибуты для включения гарантий нужного поведения?

Тут традиционный компромис:

Гарантированное поведение на одной чаше весов.

На другой, эффективность на разных платформах.

С++ решает обычно решает такие штуки в строну эффективности. С другой стороны, синтаксис языка и так сложен. Кажется, что нежелание добавлять еще опций по указанию таких штук (например, через атрибуты), тоже можно понять. Думаете пользовался бы популярностью атрибут "Не применять RVO/NRVO"?

Ну и в дополнение, можно вспомнить о том, как принимаются решения о добавлении новых особенностей в C++ :)

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

кажется, что RVO для компилятора понятнее и удобнее, чем NRVO.

Похоже что так. RVO от части перекочевало из оптимизации в правила обязательной отмены копирования. Похоже, тенденция от стандарта к стандарту в том, чтоб уменьшать серую зону, в которой компилятор сам решает применять ли RVO/NRVO или нет.

поэтому обычно считается, что после проверки if(/condition/), быстрый возврат return {}; — это хорошо.

Кроме того, отмечу, что при таком подходе (return early pattern), код становится менее громоздким и часто лучше читается, на мой взгляд.

вроде бы, он хорош со всех сторон. но получается, что шансы на получения оптимизации для нас уменьшаются?

Кажется, что да. Я проверил на clang (MacOS X). На нашем втором примере (где в двух местах return local_variable; ) NRVO был применен. В нашем первом примере, если вызвать вот так:

NRVOCheck f(int k) {
  if (k == 3)
    return NRVOCheck();
  NRVOCheck local_variable;
  // Действия с local_variable
  return local_variable;
}
f(2);

NRVO не сработал.

Как мне кажется тут как раз серая зона. RVO/NRVO может сработать, а может и нет. Зависит от компилятора, платформы и даже еще от одного факта. От того, всегда или нет выполнено условие /*condition*/. Если выполнено всегда, компилятор может понять это, и оптимизировать код, оставив одну ветку if().

Думаю, что если мы перепишем пример так:

C f() {
  C local_variable;
  if(/*condition*/)
    return local_variable;

  // Действия с local_variable
  return local_variable;  
}

шансов на NRVO прибавится.

O-большое, это с точность до константы, на которую умножается асимптотически заданное кол-ва операций (или кол-во какого-то другого ресурса. Памяти, например). Если в программе используются последовательно 2 алгоритма сложностью O(log n), то в итоге получим сложность O(log n). Так же замечу, что в общем случае сортировать массив за O(log n) не выйдет. Скорее это выйдет за O(n log n).

Да, он был бы уместен в статье. Пишут, что он обычно использует вот такой алгоритм: en.wikipedia.org/wiki/Introselect
Вероятно, добавлю его в статью.

Спасибо!
Aldrog спасибо за комментарий!

> Что подразумевается под платформой Intel?

Я полагал, что Intel пишет TBB для своих процессоров. Intel x86, вероятно эта штука будет корректно работать и для AMDx86. Это то, что я имел ввиду.

Но что вы правы. У TBB список совместимости шире, чем я думал. software.intel.com/content/www/ru/ru/develop/tools/threading-building-blocks.html

> Кстати, в большинстве дистрибутивов Linux для него есть предсобранные пакеты.

Вероятно, тогда там и с реализацией ExecutionPolicy может быть получше. Для мака пришлось собирать.
Ага. Достаточно копировать указатели. Вектору и деку для нормальной работы нужен конструктор копии. Спасибо!
На самом деле std::list::sort при обмене элементов местами не имеет дело с самими значениями, а изменяет указатели во внутренних структурах.


Интересно. Ни когда не задумывался об этом в таком ключе. Но видимо так и устроено. Так было бы логично.

Information

Rating
Does not participate
Works in
Date of birth
Registered
Activity