Форум программистов, компьютерный форум CyberForum.ru

Разница между префиксной и постфиксной формой записи счетчика цикла - C++

Восстановить пароль Регистрация
 
 
Рейтинг: Рейтинг темы: голосов - 83, средняя оценка - 4.81
limelight
7 / 7 / 0
Регистрация: 17.04.2010
Сообщений: 112
26.04.2010, 17:56     Разница между префиксной и постфиксной формой записи счетчика цикла #1
Здравствуйте!

Когда оформлял циклы всегда использовал такую запись:

C++
1
for(int i=0; i<10; i++)
, которая означает что цикл будет выполнен не более 10 раз, счетчик будет увеличен только после выполнения тела цикла и успешного выполнения условия(i<10).

В последнее время стал встречать другую запись:
C++
1
for(int i=0; i<10; ++i)
В чем принципиальное различие этих форм записей для использования цикла?
Когда какой более предпочтителен?
Similar
Эксперт
41792 / 34177 / 6122
Регистрация: 12.04.2006
Сообщений: 57,940
26.04.2010, 17:56     Разница между префиксной и постфиксной формой записи счетчика цикла
Посмотрите здесь:

Разница между i++ и ++i.Си C++
C++ Разница между != и <=
C++ Перегрузка постфиксной и префиксной операции инкремента
C++ Разница между С и С++
программа по переводу из постфиксной формы записи в инфиксную с использованием скобок C++
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 04:32     Разница между префиксной и постфиксной формой записи счетчика цикла #41
Цитата Сообщение от hoggy Посмотреть сообщение
все топовые компиляторы уже давным давно
научились оптимизировать неиспользуемые значения.
Речь в данном случае идет не о какой-то абстрактной "оптимизации неиспользуемых значений", а о вполне конкретной ситуации: устранении выполнения копирования старого значения объекта внутри нетривиальной реализации постфиксного оператора '++' в ситуации, когда это старое значение не используется снаружи, т.е. в вызове этого оператора.

Оптимизации такого рода весьма и весьма нетривиальны, в том смысле, что для не-inline вызова функций идеального способа выполнения такой оптимизации просто не существует: надо либо делать ветвление внутри реализации оператора, либо генерировать несколько версий оператора. Все варианты обладают своими достоинствами и недостатками.
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
hoggy
5225 / 2116 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
25.02.2016, 05:03     Разница между префиксной и постфиксной формой записи счетчика цикла #42
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Речь в данном случае идет не о какой-то абстрактной "оптимизации неиспользуемых значений", а о вполне конкретной ситуации: устранении выполнения копирования старого значения объекта внутри нетривиальной реализации постфиксного оператора '++' в ситуации, когда это старое значение не используется снаружи, т.е. в вызове этого оператора.
почти верно. есть нюанс.
компиляторы уже давно научились стандартным RVO/NRVO оптимизациям.
и в ситуации, когда они фиксят, что снаружи значение никому не нужно,
они запросто могут выпилить конструктор

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Оптимизации такого рода весьма и весьма нетривиальны, в том смысле, что для не-inline вызова функций идеального способа выполнения такой оптимизации просто не существует:
RVO/NRVO вообще то стандартны.
их обязаны уметь все компиляторы.
и они их умеют уже с незапамятных времен.

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

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

я хочу сказать, что совершенно не важно насколько нетривиальна функция.

компилятор оптимизирует конструкцию вида:
C++
1
obj++;
для любых типов так же просто,
как и для обычного инта.
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 05:40     Разница между префиксной и постфиксной формой записи счетчика цикла #43
Цитата Сообщение от hoggy Посмотреть сообщение
почти верно. есть нюанс.
компиляторы уже давно научились стандартным RVO/NRVO оптимизациям.
и в ситуации, когда они фиксят, что снаружи значение никому не нужно,
они запросто могут выпилить конструктор
Почти верно, но есть нюанс.

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

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

Тем не менее это ничего не меняет. Реализация оптимизаций для случая игнорируемого значения все равно требует, как я сказал выше, либо run-time branching, либо генерации нескольких версий оператора, либо еще чего-то в этом роде. Ни один из этих вариантов не является "бесплатным".

Цитата Сообщение от hoggy Посмотреть сообщение
RVO/NRVO вообще то стандартны.
Замечательно Правильнее будет сказать: разрешены стандартом. Но это никоим образом ничего не меняет. К чему это здесь?

Цитата Сообщение от hoggy Посмотреть сообщение
их обязаны уметь все компиляторы.
Нет, конечно. Оптимизация - то всегда вопрос качества реализации (quality-of-implementation). Компилятор вообще имеет право ничего не уметь оптимизировать, а просто тупо транслировать код в строгом соответствии с правилами абстрактной C++-машины.

Цитата Сообщение от hoggy Посмотреть сообщение
и они их умеют уже с незапамятных времен.
RVO существует "с незапамятных времен". NRVO же существенно более позднее изобретение - его формально не существовало в C++98.

Цитата Сообщение от hoggy Посмотреть сообщение
все очень просто: стандарт разрешает компиляторам покласть болт
на любые возможные эффекты в конструкторах копий.
Это не верно. Стандарт разрешает компиляторам покласть болт на любые возможные эффекты в конструкторах временных (безымынных) копий. Вы пропустили очень важное слово "временных". На этом принципе было основано copy elision и RVO в С++98. Позже стандарт разрешил "покласть болт" и в ряде частных, четко очерченных случаев для именованных копий, что открыло возможности для NRVO.

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

Цитата Сообщение от hoggy Посмотреть сообщение
например, когда значение снаружи все равно никому не нужно.
Опять мимо кассы. Речи идет не о том, что компилятор "может" или "не может", а о том, что его "может" не является бесплатным в сгенерированом коде и выливается либо в run-time branching, либо в code bloat.

Цитата Сообщение от hoggy Посмотреть сообщение
компилятор оптимизирует конструкцию вида:
C++Выделить код
1
obj++;
для любых типов так же просто,
как и для обычного инта.
Это совершено не верно. Оптимизация для типов, чья семантика прекрасно известна на уровне core language, и оптимизация для типов, чья семантика определена на уровне library/user code, отличается принципиально. Т.е. тут вообще даже смешно сравнивать - ничего общего эти оптимизации не имеют и ни о каком "так же просто" речи быть не может.

Собственно по этой причине мы и наблюдаем развития языка в сторону NRVO, move semantics и т.п. Эти свойства языка появились именно из-за мешающих оптимизациям принципиальных различий в семантике встроенных и пользовательских типов.
AlexVRud
413 / 142 / 36
Регистрация: 04.07.2014
Сообщений: 413
25.02.2016, 09:08     Разница между префиксной и постфиксной формой записи счетчика цикла #44
Рассматривать стоит, например, такой код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <iostream>
#include <vector>
 
int main() {
 
  std::vector<int> v {0,1,2,3,4,5,6};
  int s=0;
  for(auto i=v.cbegin(); i<v.cend(); i++) { // ++i
    s+=*i;
  }
  std::cout << s << std::endl;
 
}
При выключенной оптимизации он даст немного разный код. При оптимизации компилятор может знать, что ++i для данного итератора делает тоже но быстрее и заменит на него (а если ещё это inline, то оптимизирует ещё лучше). Но если он ничего не знает об итераторе, то выставит то, что уже есть. А теперь посмотрим на стандартный пример реализации инкремента:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Number 
{
    public:
        Number& operator++ ()     // prefix ++
        {
           // Do work on this.   (increment your object here)
           return *this;
        }
 
        // You want to make the ++ operator work like the standard operators
        // The simple way to do this is to implement postfix in terms of prefix.
        //
        Number  operator++ (int)  // postfix ++
        {
           Number result(*this);   // make a copy for result
           ++(*this);              // Now use the prefix version to do the work
           return result;          // return the copy (the old) value.
        }
};
Вспомогательный объект создан внутри Number++!!! И если его реализация скрыта (т.е. в другом файле), то компилятор не сможет оптимизировать код. Кроме этого никто не обязан давать одинаковый результат для {++i;} и {i++;}.
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 09:50     Разница между префиксной и постфиксной формой записи счетчика цикла #45
Цитата Сообщение от AlexVRud Посмотреть сообщение
Вспомогательный объект создан внутри Number++!!! И если его реализация скрыта (т.е. в другом файле), то компилятор не сможет оптимизировать код. Кроме этого никто не обязан давать одинаковый результат для {++i;} и {i++;}.
Компилятор так не оптимизирует. Компилятор не имеет права заменить 'i++' на '++i' для невстроенного типа именно потому, что, как вы правильно заметили, компилятор не знает, делают ли эти функции "одно и то же".

Возможности для оптимизации тут кроются в другом. Например, при компиляции вашего постфиксного оператора '++' компилятор может заранее подумать о том, что в некоторых контекстах этот оператор может вызываться с игнорированием результата (вариант A), а в некоторых - с неигнорированием результата (вариант B). По этой причине компилятор может использовать ваше определение постфиксного оператора '++' для того, чтобы втихаря сгенерировать две версии скомпилированного кода: для вариантов A и B отдельно. Внутренние имена для этих двух реализаций будут разные, сгенерированные в соответствии с неким соглашением. Для варианта B оператор будет странслирован честно, как вы написали - с формированием возвращаемого значения. А вот для варианта A будет странслирована "урезанная" версия без возвращаемого значения, которая элементарно соптимизируется до

C++
1
2
3
4
        void  operator++ (int)  // postfix ++
        {
           ++(*this);              // Now use the prefix version to do the work
        }
И именно эту версию умный компилятор будет потом вызывать в цикле 'for (...; ...; i++)'.

Вот об этой оптимизации и идет речь. Так, например, работает GCC. Понятно, что за такую оптимизацию приходится платить увеличением размера кода, ибо потенциально каждая функция с не-'void' типом возвращаемого значения может генерироваться в двух вариантах.
AlexVRud
413 / 142 / 36
Регистрация: 04.07.2014
Сообщений: 413
25.02.2016, 10:12     Разница между префиксной и постфиксной формой записи счетчика цикла #46
TheCalligrapher, Это он может сделать, только если видит код, если код скомпилирован в другой объектный файл, то увы, стандартного соглашения об именовании такого урезанного варианта нет.
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 10:21     Разница между префиксной и постфиксной формой записи счетчика цикла #47
Цитата Сообщение от AlexVRud Посмотреть сообщение
TheCalligrapher, Это он может сделать, только если видит код, если код скомпилирован в другой объектный файл, то увы, стандартного соглашения об именовании такого урезанного варианта нет.
Почему это? Нет, сделать это он может всегда и никакого "стандартного соглашения" тут не нужно в принципе. Соглашение тут нужно чисто внутреннее, известное только самому компилятору. Никакой необходимости что-то "стандартизовать" тут нет. Компилятор выбирает это соглашение сам для себя, и никакого кода видеть ему не нужно. Все это прекрасно работает между разными объектными файлами.
hoggy
5225 / 2116 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
25.02.2016, 10:23     Разница между префиксной и постфиксной формой записи счетчика цикла #48
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Термины RVO и NRVO в своем каноническом значении относятся именно и только к ситуациям, когда возвращаемое значение именно нужно вызывающему коду.
не принципиально.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Ситуации, когда результат вызова функции вообще никому не нужен, непосредственно к RVO и NRVO не относятся.
ещё как относится.
технология, которая позволяет компилятору удалять код запусков конструкторов.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Реализация оптимизаций для случая игнорируемого значения все равно требует, как я сказал выше, либо run-time branching,
run-time branching - противоречит понятию "оптимизации" по определению понятия "run-time branching".
это трудности компилятора, как именно он будет выкручиваться.
никаких пенальти в рантайме не будет.
на то оно и оптимизация.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
разрешены стандартом.
нет они стандарты.
они описаны стандартом.
стандарт четко говорит: как , когда, и что должно быть.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Нет, конечно.
да, конечно. стандарт - закон для компиляторов.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
RVO существует "с незапамятных времен". NRVO же существенно более позднее изобретение
вы решили устроить мне экскурсию в историю?

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
В общем случае игнорировать конструкторы именованных копий компилятору не разрешается.
познакомьтесь, ваш "общий случай":

C++
1
2
some obj1;
some obj2 = obj1; // предупреждение от компилятора: obj2 не используется
сначала он оптимизирует obj2, как не используемое значение.
затем допетрит, что obj1 так же образовалось, как не используемое.
далее он засунет свои шаловливые ручонки в конструктор obj1.
если не дотянеццо - оставит, как есть.
если дотянеццо - будет искать сайд эффекты.
если их нет - obj1 канет в лету.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
code bloat.
здесь вы переступили черту здравого смысла.

попробуйте искусственно смоделировать:
написать код вызова функции.

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

и где не используется, а значит нужно.

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

и вы получите две разные ветки кода.

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

это - единственный способ обеспечить подобную оптимизацию

вы можете считать это "платой" за оптимизацию,
и полагать это, о боже! "code bloat".

только с таким же успехом можно вообще технологию inline
так обозвать "code bloat".

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

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

классическая схема:
C++
1
2
3
4
5
6
7
8
9
10
struct counter
{
    ...    
    // ++it
    сounter& operator++(); // <--- пофиг любые сайд эффекты
 
    // it++
    counter operator++(int){ return counter(  ++(*this)); }  // <--- компилятор сказал вам "спасибо"
    ...
};

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Эти свойства языка появились именно
move семантика, не более чем вытащенная на юзерский уровень RVO/NRVO
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 10:38     Разница между префиксной и постфиксной формой записи счетчика цикла #49
Цитата Сообщение от hoggy Посмотреть сообщение
run-time branching - противоречит понятию "оптимизации" по определению понятия "run-time branching".
Это не верно. Если выигрыш от run-time branching превосходит потери на run-time branching - то получается прекрасная оптимизация. Тут все просто.

Цитата Сообщение от hoggy Посмотреть сообщение
нет они стандарты.
они описаны стандартом.
стандарт четко говорит: как , когда, и что должно быть.
Нет, ни в коем случае. Это вы, очевидно, с Java перепутали. Стандарт С++ где-то говорит "как, когда, и что должно быть", а где-то не говорит. Стандарт С++ знаменит тем, что содержит огромное количество мест, в которых поведение undefined, unspecified или implementation-defined, т.е. стандартом не оговаривается вообще. А уж об "оптимизациях" даже и говорить смешно - ни о каком "как, когда, и что должно быть" не может быть и речи и ничего подобного в стандарте нет.

Цитата Сообщение от hoggy Посмотреть сообщение
вы решили устроить мне экскурсию в историю?
Кто бы говорил...

Цитата Сообщение от hoggy Посмотреть сообщение
здесь вы переступили черту здравого смысла.
...
не пишут всякий бред под капотом единицы трансляции.
Тут вообще пошел какой-то поток сознания с приплетением совершенно посторонних вещей, типа inline... Непропарсил.

Цитата Сообщение от hoggy Посмотреть сообщение
классическая схема:
C++
1
2
3
4
5
6
7
8
9
struct counter
{
    ...
    // ++it
    сounter& operator++(); // <--- пофиг любые сайд эффекты
    // it++
    counter operator++(int){ return counter(  ++(*this)); } *// <--- компилятор сказал вам "спасибо"
    ...
};
Что это? Этот код - какая-то бессмыслица. К чему это здесь?

Цитата Сообщение от hoggy Посмотреть сообщение
move семантика, не более чем вытащенная на юзерский уровень RVO/NRVO
Ым... Нет, move semantics ничего общего с RVO/NRVO не имеют даже отдаленно. Более того, в контексте возвращаемых значений функции это взаимоисключающие способы оптимизации.
AlexVRud
413 / 142 / 36
Регистрация: 04.07.2014
Сообщений: 413
25.02.2016, 10:51     Разница между префиксной и постфиксной формой записи счетчика цикла #50
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Почему это?
Потому что, если метод объявлен не как inline и его реализация хранится в другом файле, то максимум, что может сделать компилятор, так это по всем правилам вызвать конкретную внешнюю функцию, например, _ZN6NumberppEi.

Добавлено через 1 минуту
Т.е. выделить место для временного объекта, его получить и разрушить
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 10:58     Разница между префиксной и постфиксной формой записи счетчика цикла #51
Цитата Сообщение от AlexVRud Посмотреть сообщение
Потому что, если метод объявлен не как inline и его реализация хранится в другом файле, то максимум, что может сделать компилятор, так это по всем правилам вызвать конкретную внешнюю функцию, например, _ZN6NumberppEi.
Совершенно верно! Поэтому компилятор тихонько сам с собой договаривается, чисто для себя, безо всяких "стандартов", что полноценный метод будет экспортироваться как '_ZN6NumberppEi', а урезанный - как '_ZN6NumberppEikvakva'. И все. Именно так поступает GCC, к примеру.
AlexVRud
413 / 142 / 36
Регистрация: 04.07.2014
Сообщений: 413
25.02.2016, 11:35     Разница между префиксной и постфиксной формой записи счетчика цикла #52
TheCalligrapher, Посмотри на результат, я там ничего не вижу кроме _ZN6NumberppEi в объектом файле и его вызове в итоговом.

Добавлено через 18 минут
for.h:
C++
1
2
3
4
5
6
7
class Number {
  int i[100];
public:
  Number& operator++ ();
  Number operator++ (int);
  ~Number();
};
for.cpp:
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include "for.h"
 
Number& Number::operator++() {
  ++i[0];
  return *this;
 };
 
Number  Number::operator++ (int) {
  Number result(*this);   // make a copy for result
  ++(*this);              // Now use the prefix version to do the work
  return result;          // return the copy (the old) value.
}
 
Number::~Number() {
}
main.cpp:
C++
1
2
3
4
5
6
7
#include "for.h"
 
int main() {
  Number a;
  a++;
  return 0;
}
Результат при -O3

Assembler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
00000000004005c0 <main>:
  4005c0:       53                      push   %rbx
  4005c1:       31 d2                   xor    %edx,%edx
  4005c3:       48 81 ec 20 03 00 00    sub    $0x320,%rsp
  4005ca:       48 8d bc 24 90 01 00    lea    0x190(%rsp),%rdi
  4005d1:       00 
  4005d2:       48 89 e6                mov    %rsp,%rsi
  4005d5:       e8 36 01 00 00          callq  400710 <_ZN6NumberppEi>
  4005da:       48 8d bc 24 90 01 00    lea    0x190(%rsp),%rdi
  4005e1:       00 
  4005e2:       e8 79 01 00 00          callq  400760 <_ZN6NumberD1Ev>
  4005e7:       48 89 e7                mov    %rsp,%rdi
  4005ea:       e8 71 01 00 00          callq  400760 <_ZN6NumberD1Ev>
  4005ef:       48 81 c4 20 03 00 00    add    $0x320,%rsp
  4005f6:       31 c0                   xor    %eax,%eax
  4005f8:       5b                      pop    %rbx
  4005f9:       c3                      retq   
  4005fa:       48 89 c3                mov    %rax,%rbx
  4005fd:       48 89 e7                mov    %rsp,%rdi
  400600:       e8 5b 01 00 00          callq  400760 <_ZN6NumberD1Ev>
  400605:       48 89 df                mov    %rbx,%rdi
  400608:       e8 a3 ff ff ff          callq  4005b0 <_Unwind_Resume@plt>
  40060d:       0f 1f 00                nopl   (%rax)
hoggy
5225 / 2116 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
25.02.2016, 19:07     Разница между префиксной и постфиксной формой записи счетчика цикла #53
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Это вы, очевидно, с Java перепутали.
RVO/NRVO - стандартные оптимизации.

вы никогда не задумывались, почему их называют "стандартными?

http://en.cppreference.com/w/cpp/language/copy_elision

священного писания нет под рукой.
однако, вы можете сами проверить и убедиться:
они там описаны.
12.8 Copying and moving class objects [class.copy]
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
типа inline... Непропарсил.
вы там выше писали, что у подобных оптимизаций есть своя цена.
либо пенальти в рантайме, либо разбухание кода.

ну так вот, оптимизация конструкторов устраняет пенальти в рантайме.
а что касается разбухания кода - с тем же успехом, можно сказать,
что у inline есть своя цена - о боже!
inline подстановка приводит к увеличению объемов кода!

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Что это? Этот код - какая-то бессмыслица. К чему это здесь?
к тому, что если вы скомпилите это в релизе, оптимизация по скорости,
то окажется, что для случаев, когда результат можно отбросить,
компилятор оптимизировал простфикс до префикса.

определенные в теле класса методы являются inline
компилятору доступен контекст.
он оптимизирует ненужный временный объект,
в результате остается только префикс.

то есть, тут даже никакого разбухания кода не происходит.

Цитата Сообщение от AlexVRud Посмотреть сообщение
то максимум, что может сделать компилятор
ему ничего не мешает похерить строительство
никому не нужного объекта.
TheCalligrapher
С чаем беда...
Эксперт С++
 Аватар для TheCalligrapher
2785 / 1431 / 393
Регистрация: 18.10.2014
Сообщений: 2,629
25.02.2016, 20:05     Разница между префиксной и постфиксной формой записи счетчика цикла #54
Цитата Сообщение от hoggy Посмотреть сообщение
RVO/NRVO - стандартные оптимизации.
вы никогда не задумывались, почему их называют "стандартными?
Их называют стандартными потому, что они разрешены стандартом.

Цитата Сообщение от hoggy Посмотреть сообщение
священного писания нет под рукой.
однако, вы можете сами проверить и убедиться:
они там описаны.
О том, что они там описаны вам сообщил я. Причем я также сообщил вас, как они там описаны: именно как оптимизации, т.е. что-то, что компилятор может, но не обязан делать. Поэтому зачем вы нам тут пытаетесь напускать туману глубокомысленными разглагольствованиями о том, что "оптимизации называют стадартными" и что "они там описаны" - мне не понятно. Мы все здесь об это прекрасно знаем. К чему это здесь?

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

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

Цитата Сообщение от hoggy Посмотреть сообщение
что у inline есть своя цена - о боже!
inline подстановка приводит к увеличению объемов кода!
Совершенно верно. Именно поэтому inline-подстановка не выполняется безусловно, а основана на решении, принимаем компилятором на основе каких-то внутренних эмпирических/эвристических критериев, в том числе учитывающих вопросы разбухания кода и конфигурационные параметры, заданные пользователем. Компилятор может решить выполнить inline-подстановку, а может решить не выполнить. Другими словами, в общем случае inline-подстановки не делается и рассчитывать на то, что она произойдет - нельзя. То же самое относится и к рассматриваемому вопросу: сколько бы вы ни придумывали оптимизаций, скрывающих разницу в производительности между префиксным и постфиксным инкрементом, помните, что по той или иной причине в общем случае эти оптимизации выполняться не будут.

Цитата Сообщение от hoggy Посмотреть сообщение
к тому, что если вы скомпилите это в релизе, оптимизация по скорости,
то окажется, что для случаев, когда результат можно отбросить,
компилятор оптимизировал простфикс до префикса.
Еще раз: приведенный вам код некорректен и бессмысленен. Поэтому никакого разговора о каких-то оптимизациях в отношении этого кода быть не может. Возьмите в привычку читать свой код внимательнее, перед тем как постить его на всеобщее обозрение, чтобы в будущем избегать подобных конфузов.
hoggy
5225 / 2116 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
25.02.2016, 20:39     Разница между префиксной и постфиксной формой записи счетчика цикла #55
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Их называют стандартными потому, что они разрешены стандартом.
нет, их называют стандартными, потому что они стандартизированы.
ваш Кэп.

стандарт вообще никому ничего не запрещает.
Кэпа можно не благодарить.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
К чему это здесь?
к тому, что компиляторы обязаны уметь выполнять такие оптимизации.
и они это делают.

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Прямые цитаты из стандарта приведите, пжлст.
там выше я привел ссылку на референс.
и ссылку на параграф.
Цитата Сообщение от TheCalligrapher Посмотреть сообщение
а основана на решении
на решении программиста.
программист сказал - максимальная скорость, и понеслось...

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
Другими словами, в общем случае inline-подстановки не делается и рассчитывать на то, что она произойдет - нельзя.
компилятор выполняет просьбу программиста всегда,
когда есть такая техническая возможность,
и это не противоречит стратегии оптимизации.

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

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

Цитата Сообщение от TheCalligrapher Посмотреть сообщение
приведенный вам код некорректен и бессмысленен
C++
1
2
3
4
5
6
    iterator operator++(int) 
    {
        const auto copy = *this; 
        operator++(); 
        return copy;
    }
gru74ik
Модератор
 Аватар для gru74ik
3080 / 1325 / 164
Регистрация: 20.02.2013
Сообщений: 3,768
Записей в блоге: 17
25.02.2016, 21:23     Разница между префиксной и постфиксной формой записи счетчика цикла #56
Цитата Сообщение от hoggy Посмотреть сообщение
священного писания нет под рукой
hoggy, вот тут лежит черновик стандарта C++14 (Document Number: N3797).
ct0r
C++/Haskell
 Аватар для ct0r
1549 / 568 / 39
Регистрация: 19.08.2012
Сообщений: 1,174
Завершенные тесты: 1
25.02.2016, 22:34     Разница между префиксной и постфиксной формой записи счетчика цикла #57
hoggy, сможешь продемонстрировать, что, например, постфикс от std::istream_iterator<std::string>действительно оптимизируется всеми распространенными компиляторами?
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
25.02.2016, 23:22     Разница между префиксной и постфиксной формой записи счетчика цикла
Еще ссылки по теме:

C++ перегрузка постфиксной и префиксной формы оператора ++
C++ ++i и i++ разница при выполнении цикла
C++ Как сделать чтобы в постфиксной записи кроме цифр выводились еще и обычные символы

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
hoggy
5225 / 2116 / 403
Регистрация: 15.11.2014
Сообщений: 4,800
Завершенные тесты: 1
25.02.2016, 23:22     Разница между префиксной и постфиксной формой записи счетчика цикла #58
Цитата Сообщение от ct0r Посмотреть сообщение
сможешь продемонстрировать, что, например, постфикс от std::istream_iterator<std::string>действительно оптимизируется всеми распространенными компиляторами?
нет.
Yandex
Объявления
25.02.2016, 23:22     Разница между префиксной и постфиксной формой записи счетчика цикла
Ответ Создать тему
Опции темы

Текущее время: 11:13. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru