Существует ли различие в производительности между мной ++ и ++ я в C++?

Я скорректировал ответ Гленна Мосса, чтобы учесть тот факт, что div overflow не может находиться в верхней части страницы.

parentDiv.scrollTop(parentDiv.scrollTop() + (innerListItem.position().top - parentDiv.position().top) - (parentDiv.height()/2) + (innerListItem.height()/2)  )

Я использовал это в приложении с картами Google с помощью отзывчивый шаблон. При разрешении> 800 пикселей список находился в левой части карты. По разрешению & lt; 800 этот список был ниже карты.

341
задан Mark Harrison 11 September 2016 в 19:41
поделиться

11 ответов

[Резюме: Используйте ++i, если у Вас нет определенной причины использовать i++.]

Для C++, ответ немного более сложен.

, Если i простой тип (не экземпляр класса C++), тогда ответ, данный для C ("Нет нет никакого различия в производительности") , содержит, так как компилятор генерирует код.

Однако, если i экземпляр класса C++, то i++ и ++i выполняют вызовы к одному из operator++ функции. Вот стандартная пара этих функций:

Foo& Foo::operator++()   // called for ++i
{
    this->data += 1;
    return *this;
}

Foo Foo::operator++(int ignored_dummy_value)   // called for i++
{
    Foo tmp(*this);   // variable "tmp" cannot be optimized away by the compiler
    ++(*this);
    return tmp;
}

, Так как компилятор не генерирует код, но просто звонит operator++ функция, нет никакого способа оптимизировать далеко tmp переменная и ее связанный конструктор копии. Если конструктор копии является дорогим, то это может оказать значительное влияние производительности.

416
ответ дан zar 23 November 2019 в 00:35
поделиться

@wilhelmtell

компилятор может игнорировать временный файл. Дословно от другого потока:

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

http://msdn.microsoft.com/en-us/library/ms364057 (По сравнению с 80) .aspx

1
ответ дан Tim Cooper 23 November 2019 в 00:35
поделиться

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

О преждевременной оптимизации, Knuth часто заключается в кавычки.Верно. но Donald Knuth никогда не защищал бы с этим ужасный код, который Вы видите в эти дни. Когда-нибудь замеченный = b + c среди Целых чисел Java (не интервал)? Это составляет 3 преобразования упаковки/распаковывания. Предотвращение материала как этот важно. И бесполезно при записи i ++ вместо ++ я - та же ошибка.Править: Как phresnel приятно выражается в комментарии, этому можно подвести итог, поскольку "преждевременная оптимизация является злой, как преждевременный pessimization".

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

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

0
ответ дан 2 revs 23 November 2019 в 00:35
поделиться

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

0
ответ дан Josh 23 November 2019 в 00:35
поделиться

Mark: Просто требуемый, чтобы указать, что оператор ++ является хорошими кандидатами, чтобы быть встроенным, и если компилятор выбирает делать так, избыточная копия будет устранена в большинстве случаев. (например, типы POD, которые обычно итераторы.)

Однако это - еще лучший стиль для использования ++ проход в большинстве случаев.:-)

3
ответ дан 0124816 23 November 2019 в 00:35
поделиться

@Ketan

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

, Очевидно, сообщение и преинкремент имеют различную семантику, и я уверен, что все соглашаются, что, когда результат используется, необходимо использовать соответствующий оператор. Я думаю, что вопрос - то, что должно каждый делать, когда результат отбрасывается (как в for циклы). Ответ на этот вопрос (по моему скромному мнению), состоит в том, что, так как соображения производительности незначительны в лучшем случае необходимо сделать то, что является более естественным. Для меня ++i является более естественным, но мой опыт говорит мне, что я нахожусь в меньшинстве, и использование i++ вызовет меньше металла наверху для большинство люди, читающие Ваш код.

, В конце концов, это - причина, которой язык не называют" ++C ". [*]

[*] Вставляют обязательное обсуждение [приблизительно 114] являющиеся более логическим именем.

4
ответ дан Motti 23 November 2019 в 00:35
поделиться

Я хотел бы указать на превосходное сообщение Andrew Koenig на Разговоре о Коде совсем недавно.

http://dobbscodetalk.com/index.php?option=com_myblog&show=Efficiency-versus-intent.html&Itemid=29

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

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

4
ответ дан 23 November 2019 в 00:35
поделиться

в Руководстве по стилю C++ Google говорится:

Преинкремент и Преддекремент

форма префикса Использования (++ i) инкрементных и операторов понижения с итераторами и другими объектами шаблона.

Определение: , Когда переменная увеличена (++ я или я ++) или постепенно уменьшилась (-я или я-) и значение выражения не используется, нужно решить ли к преинкременту (декремент) или постинкремент (декремент).

Профессионалы: то, Когда возвращаемое значение проигнорировано, "пред" форма (++ i) никогда не менее эффективно, чем форма "сообщения" (я ++) и часто более эффективно. Это вызвано тем, что постинкремент (или декремент) требует, чтобы копия меня была сделана, который является значением выражения. Если я - итератор или другой нескалярный тип, копируя я мог бы быть дорогим. Так как два типа инкремента ведут себя то же, когда значение проигнорировано, почему не только всегда преинкремент?

Недостатки: разработанная традиция, в C, использования постинкремента, когда значение выражения не используется, особенно в для циклов. Некоторые находят постинкремент легче читать, так как "предмет" (i) предшествует "глаголу" (++), точно так же, как на английском языке.

Решение: Для простых скалярных (необъектных) значений нет никакой причины предпочесть одну форму, и мы позволяем также. Для итераторов и других шаблонных типов, используйте преинкремент.

14
ответ дан Cees Timmerman 23 November 2019 в 00:35
поделиться

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

В следующем примере, сгенерированный код идентичен для префикса и постфикса, например:

#include <stdio.h>

class Foo
{
public:

    Foo() { myData=0; }
    Foo(const Foo &rhs) { myData=rhs.myData; }

    const Foo& operator++()
    {
        this->myData++;
        return *this;
    }

    const Foo operator++(int)
    {
        Foo tmp(*this);
        this->myData++;
        return tmp;
    }

    int GetData() { return myData; }

private:

    int myData;
};

int main(int argc, char* argv[])
{
    Foo testFoo;

    int count;
    printf("Enter loop count: ");
    scanf("%d", &count);

    for(int i=0; i<count; i++)
    {
        testFoo++;
    }

    printf("Value: %d\n", testFoo.GetData());
}

, Делаете ли Вы ++ testFoo или testFoo ++, Вы все еще получите тот же получающийся код. На самом деле, не читая количество в от пользователя, оптимизатор снизил все это к константе. Так это:

for(int i=0; i<10; i++)
{
    testFoo++;
}

printf("Value: %d\n", testFoo.GetData());

Привел к следующему:

00401000  push        0Ah  
00401002  push        offset string "Value: %d\n" (402104h) 
00401007  call        dword ptr [__imp__printf (4020A0h)] 

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

20
ответ дан James Sutherland 23 November 2019 в 00:35
поделиться

Да. Существует.

++ оператор может или не может быть определен как функция. Для типов примитивов (интервал, дважды...) встроены операторы, таким образом, компилятор, вероятно, будет в состоянии оптимизировать Ваш код. Но в случае объекта, который определяет ++, вещи оператора отличаются.

оператор ++ (международная) функция должна создать копию. Это вызвано тем, что постфикс ++, как ожидают, возвратит различное значение, чем, что он содержит: это должно содержать свое значение во временной переменной, увеличить его значение и возвратить временный файл. В случае оператора ++ (), префикс ++, нет никакой потребности создать копию: объект может увеличить себя и затем просто возвратить себя.

Вот иллюстрация точки:

struct C
{
    C& operator++();      // prefix
    C  operator++(int);   // postfix

private:

    int i_;
};

C& C::operator++()
{
    ++i_;
    return *this;   // self, no copy created
}

C C::operator++(int ignored_dummy_value)
{
    C t(*this);
    ++(*this);
    return t;   // return a copy
}

Каждый раз, когда Вы называете оператор ++ (интервал), необходимо создать копию, и компилятор ничего не может делать с этим. Когда дали выбор, используйте оператор ++ (); этим путем Вы не сохраняете копию. Это могло бы быть значительно в случае многих инкрементов (большой цикл?) и/или большие объекты.

62
ответ дан lc. 23 November 2019 в 00:35
поделиться

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

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

Если доля времени ЦП, затрачиваемая на увеличение итераторов, составляет менее 10%, тогда вам может быть все равно.

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

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

1
ответ дан 23 November 2019 в 00:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: