Есть ли разница в производительности между i ++ и ++ i в C ++? - PullRequest

Ответы [ 18 ]

1 голос
/ 23 августа 2009

@ Марк: я удалил свой предыдущий ответ, потому что это было немного перевернуто, и заслужил понижение за это одно. Я на самом деле думаю, что это хороший вопрос в том смысле, что он спрашивает, что думают многие люди.

Обычный ответ таков: ++ я быстрее, чем i ++, и, без сомнения, так и есть, но главный вопрос - «когда тебя это волнует?»

Если доля процессорного времени, потраченного на инкрементные итераторы, составляет менее 10%, то вам может быть все равно.

Если доля процессорного времени, затрачиваемого на инкрементные итераторы, превышает 10%, вы можете посмотреть, какие операторы выполняют эту итерацию. Посмотрите, можете ли вы просто увеличивать целые числа, а не использовать итераторы. Скорее всего, вы могли бы, и хотя это может быть в некотором смысле менее желательно, шансы довольно хороши, вы сэкономите практически все время, проведенное в этих итераторах.

Я видел пример, когда увеличение итератора потребляло более 90% времени. В этом случае переход к целочисленному приращению сокращает время выполнения по существу на эту величину. (т.е. лучше, чем 10-кратное ускорение)

1 голос
/ 27 августа 2008

@ wilhelmtell

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

Компилятору C ++ разрешено устранять временные эффекты на основе стека, даже если это изменяет поведение программы. Ссылка MSDN для VC 8:

http://msdn.microsoft.com/en-us/library/ms364057(VS.80).aspx

1 голос
/ 25 августа 2008

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

1 голос
/ 29 марта 2018

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

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

#include <iostream>

class Data {
    private: class DataIncrementer {
        private: Data& _dref;

        public: DataIncrementer(Data& d) : _dref(d) {}

        public: ~DataIncrementer() {
            ++_dref;
        }
    };

    private: int _data;

    public: Data() : _data{0} {}

    public: Data(int d) : _data{d} {}

    public: Data(const Data& d) : _data{ d._data } {}

    public: Data& operator=(const Data& d) {
        _data = d._data;
        return *this;
    }

    public: ~Data() {}

    public: Data& operator++() { // prefix
        ++_data;
        return *this;
    }

    public: Data operator++(int) { // postfix
        DataIncrementer t(*this);
        return *this;
    }

    public: operator int() {
        return _data;
    }
};

int
main() {
    Data d(1);

    std::cout <<   d << '\n';
    std::cout << ++d << '\n';
    std::cout <<   d++ << '\n';
    std::cout << d << '\n';

    return 0;
}

Изобретен для некоторого тяжелого пользовательского кода итераторов, и он сокращает время выполнения. Стоимость префикса по сравнению с постфиксом теперь является одной ссылкой, и если это пользовательский оператор, выполняющий тяжелые перемещения, префикс и постфикс дают мне одно и то же время выполнения.

1 голос
/ 15 января 2009

Предполагаемый вопрос был о том, когда результат не используется (это ясно из вопроса для C). Кто-нибудь может это исправить, так как вопрос «сообщество вики»?

О преждевременных оптимизациях Кнут часто цитируют. Вот так. но Дональд Кнут никогда не защитит с этим ужасным кодом, который вы можете видеть в эти дни. Вы когда-нибудь видели a = b + c среди Java Integer (не int)? Это составляет 3 конверсии в бокс / распаковку. Важно избегать подобных вещей. И бесполезно писать i ++ вместо ++ i - это та же ошибка. РЕДАКТИРОВАТЬ: Как хорошо говорит Френель в комментарии, это можно суммировать как «преждевременная оптимизация - зло, так же как и преждевременная пессимизация».

Даже тот факт, что люди более привыкли к i ++, является печальным наследием C, вызванным концептуальной ошибкой K & R (если вы следуете аргументу намерения, это логичный вывод; и защищать K & R, потому что они K & R, не имеет смысла, они хороши, но они не так хороши, как разработчики языков: в дизайне C существует множество ошибок, от get () до strcpy (), до API strncpy () (он должен был иметь API strlcpy (), так как день 1)).

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

0 голосов
/ 11 апреля 2011

Оба так же быстро;) Если вы хотите, чтобы это был тот же самый расчет для процессора, это просто порядок, в котором это делается, которые отличаются.

Например, следующий код:

#include <stdio.h>

int main()
{
    int a = 0;
    a++;
    int b = 0;
    ++b;
    return 0;
}

Произведите следующую сборку:

 0x0000000100000f24 <main+0>: push   %rbp
 0x0000000100000f25 <main+1>: mov    %rsp,%rbp
 0x0000000100000f28 <main+4>: movl   $0x0,-0x4(%rbp)
 0x0000000100000f2f <main+11>:    incl   -0x4(%rbp)
 0x0000000100000f32 <main+14>:    movl   $0x0,-0x8(%rbp)
 0x0000000100000f39 <main+21>:    incl   -0x8(%rbp)
 0x0000000100000f3c <main+24>:    mov    $0x0,%eax
 0x0000000100000f41 <main+29>:    leaveq 
 0x0000000100000f42 <main+30>:    retq

Вы видите, что для a ++ и b ++ это мнемоника вкл, так что это та же самая операция;)

0 голосов
/ 29 марта 2018

Когда вы пишете i++, вы указываете компилятору увеличивать его после завершения этой строки или цикла.

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

0 голосов
/ 08 марта 2014

++i быстрее i++, поскольку не возвращает старую копию значения.

Это также более интуитивно понятно:

x = i++;  // x contains the old value of i
y = ++i;  // y contains the new value of i 

В этом примере C печатается "02" вместо "12", который вы можете ожидать:

#include <stdio.h>

int main(){
    int a = 0;
    printf("%d", a++);
    printf("%d", ++a);
    return 0;
}

То же самое для C ++ :

#include <iostream>
using namespace std;

int main(){
    int a = 0;
    cout << a++;
    cout << ++a;
    return 0;
}
...