[Закрываются] общие подсказки по повышению производительности C++

Кто-то мог указать на меня на статью или записать некоторые подсказки прямо здесь о некоторых привычках программирования на C++, которые обычно допустимы (никакие реальные недостатки), и улучшает производительность? Я не имею в виду шаблоны программирования и сложность алгоритма - мне нужны мелочи как то, как Вы определяете свои функции, вещи/к избегают в циклах, что выделить на стеке, что на "куче", и так далее.

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

49
задан Ronan Boiteau 22 August 2018 в 05:14
поделиться

23 ответа

[
    ] [
  • ] Избегайте множественного наследования. [
  • ] [
  • ]Используйте виртуалы, когда они необходимы, а не только для забавы[
  • ] [
  • ]Используйте классы коллекции шаблонов только тогда, когда это больно не[
  • ] [
]
0
ответ дан 7 November 2019 в 11:17
поделиться
[

] Здесь уже много хороших предложений. [

] [

] Один из лучших способов вжиться в хорошие привычки - это навязать их себе. За это я люблю PC-Lint. PC-Lint на самом деле обеспечит соблюдение правил С++ и более эффективных С++ Скотта Мейера. Кроме того, соблюдение правил Lint, как правило, приводит к тому, что код становится проще в обслуживании, меньше подвержен ошибкам и чище. Только не сходите с ума, если вы понимаете, что lint часто генерирует больше вывода, чем у вас есть в исходном коде; однажды я работал над проектом с исходным кодом 150MB и 1.8GB сообщений Lint.[

].
1
ответ дан 7 November 2019 в 11:17
поделиться
[

][][]Эта страница суммирует все, что вы должны знать об оптимизации на Си++ (будь то во время или после написания программного обеспечения).[][] Это действительно хороший совет и очень познавательно -- и может быть использовано в качестве полезного напоминания на этапе оптимизации в проекте.[

] [

]Она немного старая, так что вы также должны знать, какие оптимизации уже сделаны вашим компилятором (например, NRVO). [

] [

]Кроме того, чтение уже процитированных стандартов кодирования Effective C++, More Effective C++, Effective STL и C++ Coding Standards также важно, так как они многое объясняют о том, что происходит в языке и в STL, позволяя лучше оптимизировать конкретный случай, используя лучшее понимание того, что именно происходит.[

].
2
ответ дан 7 November 2019 в 11:17
поделиться
[

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

] [

] Одним из примеров всегда является использование умных указателей вместо необработанных указателей для контроля времени жизни кучи памяти. Другой, конечно же, связан с развитием привычки всегда использовать RAII для получения и освобождения ресурсов. Другой - всегда использовать исключения для обработки ошибок. Эти три правила, как правило, упрощают код, тем самым делая его меньше и быстрее, а также проще для понимания. [
][

] [

] Можно также сделать геттеры и сеттеры неявно встроенными; всегда полностью использовать списки инициализаторов в конструкторах; и всегда использовать функции find и другие связанные с ними функции, которые предоставляются в std-библиотеке, вместо того, чтобы создавать собственные циклы. [

] [

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

] [

] И еще одно - не копируйте код из одного места в другое, если вам нужна функциональность - используйте функцию. Это уменьшает размер кода и облегчает оптимизацию всех мест, использующих данную функциональность.[

].
5
ответ дан 7 November 2019 в 11:17
поделиться
[

]Шаблоны! Использование шаблонов может сократить объем кода, так как можно иметь класс или функцию/метод, которые могут быть многократно использованы со многими типами данных.[

] [

]Рассмотрим следующее:[

] [
#include <string>
using std::basic_string;

template <class T>
    void CreateString(basic_string<T> s)
    {
        //...
    }
] [

]Основная_строка может состоять из char, wchar_t, unsigned char или unsigned wchar_t.[

] [

]Шаблоны также могут быть использованы для множества различных вещей, таких как трейты, специализация класса, или даже использоваться для передачи значения int в класс![

]
4
ответ дан 7 November 2019 в 11:17
поделиться
[

] Из Вашего вопроса кажется, что Вы уже знаете о философии "преждевременная оптимизация - это зло", так что проповедовать об этом я не буду. :)[

] [

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

] [

]Для небольших "оптимизаций" можно безопасно обойтись без раздумий, что не сильно влияет на читабельность/сохранение кода, посмотрите раздел "Premature Pessimization" книги []C++ Coding Standards[] by Sutter & Alexandrescu.[

] [

]Для более детальных техник оптимизации посмотрите []Efficient C++[] by Bulka & Mayhew. Используйте только тогда, когда это оправдано профилированием![

] [

]Для хорошей общей практики программирования на С++ смотрите:[

] [
    ] [
  • ][]C++ Coding Standards[] by Sutter & Alexandrescu (должно быть, IMHO)[
  • ] [
  • ][]Effective C++/STL series[] by Scott Meyers[
  • ] [
  • ][]Exceptional C++[] by Herb Sutter[
  • ] [
] [

]Off the top of my head, one good general performance practice is to pass heavyweight objects by reference, instead by copy. Например:[

] [
// Not a good idea, a whole other temporary copy of the (potentially big) vector will be created.
int sum(std::vector<int> v)
{
   // sum all values of v
   return sum;
}

// Better, vector is passed by constant reference
int sum(const std::vector<int>& v)
{
   // v is immutable ("read-only") in this context
   // sum all values of v.
   return sum;
}
] [

]Для небольшого объекта, такого как комплексное число или 2-мерная (x, y) точка, функция, скорее всего, будет работать быстрее с объектом, переданным по ссылке.[

] [

]Когда дело доходит до объектов фиксированного размера и среднего веса, не так понятно, будет ли функция работать быстрее с копией или ссылкой на объект. Только профилирование покажет. Обычно я просто передаю const reference (если функция не нуждается в локальной копии) и беспокоюсь об этом, только если профилирование подсказывает.[

] [

]Некоторые скажут, что можно встраивать небольшие методы класса, не задумываясь. Это может дать вам прирост производительности во время выполнения, но это также может удлинить время компиляции, если есть большое количество встраиваемых методов. Если метод класса является частью библиотечного API, возможно, лучше не встраивать его, не важно насколько он маленький. Это связано с тем, что реализация встроенных функций должна быть видна другим модулям/классам. Если вы что-то измените в этой встроенной функции/методе, то другие модули, на которые она ссылается, должны быть перекомпилированы.[

] [

]Когда я только начинал программировать, я пытался микро-оптимизировать все (это был инженер-электрик во мне). Какая пустая трата времени![

] [

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

]
8
ответ дан 7 November 2019 в 11:17
поделиться
[

] Почему об этом до сих пор никто не упоминал? Почему всем нравится бедняжка [] ++i []? [

] [

] Одна из лучших маленьких вещей, которые вы можете легко сделать, чтобы [] не пессимизировать [] ваш код: [

] [

][] Эффективный C++ [] [] Скотта Мейерса [], пункт 20: [

] [

][] Предпочитают передавать по ссылке к константе, чтобы передать значение по ссылке [][

] [

] Пример: [

] [
// this is a better option
void some_function(const std::string &str);
// than this:
void some_function(std::string str);
] [

]В случае короткого []std::string[] вы можете выиграть не очень много, но передача []больших [] объектов вроде этого, может сэкономить вам довольно много вычислительной мощности, так как вы избегаете избыточного копирования. А также может избавить вас от пары ошибок, если вы забыли реализовать свой конструктор копирования.[

].
0
ответ дан 7 November 2019 в 11:17
поделиться

Лучший способ улучшить эти навыки - это читать книги и статьи, но я могу помочь вам некоторыми советами:

  • 1- Принимайте объекты по ссылке и примитивные типы или типы указателей по значению, но используйте указатель на объект, если функция хранит ссылка или указатель на объект.
  • 2- Не используйте МАКРОСЫ для объявления констант -> используйте static const.
  • 3- Всегда реализуйте виртуальный деструктор, если ваш класс может быть подклассом.
0
ответ дан 7 November 2019 в 11:17
поделиться
  1. Избегайте фрагментации памяти.
  2. Выровненная память.
  3. Инструкции SIMD.
  4. Безблокированная многопоточность.
  5. Используйте соответствующие деревья ускорения, такие как kd-дерево, покровное дерево, октавр, квадтрио и т.д. 5a. Определите их таким образом, чтобы первые три (т.е. сделайте все узлы в одном блоке)
  6. вклинивания. Самый нижний висячий, но довольно вкусный фрукт.

Удивительно, как можно увеличить производительность. Для меня 1500 раз за тяжелое вычислительное приложение. Не более грубого носа, а более похожих структур данных, написанных в основном программном пакете.

Я бы не стал зацикливаться на этом, как преинкремент над постом. Это даёт экономию только в определённых (неважных) случаях, и большинство из того, что упоминается, это похожие вещи, которые могут отскребать лишний 1% здесь и там время от времени, но обычно не стоят того, чтобы беспокоиться.

1
ответ дан 7 November 2019 в 11:17
поделиться

Несколько моих любимых раздражений:

  1. Не объявляйте (фактически, не определяйте) объектные переменные перед их использованием / инициализацией (как в C). Это требует, чтобы выполнялись функции конструктора И оператора присваивания, а для сложных объектов это может быть дорогостоящим.
  2. Предпочитайте пре-инкремент пост-инкременту. Это будет иметь значение только для итераторов и определяемых пользователем типов с перегруженными операторами.
  3. Используйте минимально возможные примитивные типы. Не используйте long int для хранения значения в диапазоне 0..5. Это уменьшит общее использование памяти, улучшит локальность и, следовательно, общую производительность.
  4. Используйте динамическую память (динамическое выделение) только при необходимости. Многие программисты на C ++ по умолчанию используют кучу. Динамические выделения и освобождение дорогие.
  5. Сведите к минимуму использование временных файлов (особенно при обработке строк). Страуструп представляет хорошую технику для определения логического эквивалента тернарных арифметических операторов и арифметических операторов высшего порядка в «Языке программирования C ++»
  6. . Знайте свои параметры компилятора / компоновщика. Также знайте, какие из них вызывают нестандартное поведение. Это резко влияет на производительность во время выполнения.
  7. Знайте компромисс между производительностью и функциональностью контейнеров STL (например, не вставляйте часто в вектор, используйте список).
  8. Не инициализируйте переменные, объекты, контейнеры и т. Д., Если они должны быть безоговорочно присвоены.
  9. Обратите внимание на порядок вычисления сложных условных выражений. Например, для if (a && b) , если b с большей вероятностью будет ложным, поместите его первым, чтобы сохранить оценку a.

Есть много других «вредных привычек», о которых я не буду упоминать, потому что на практике современные компиляторы / оптимизаторы устраняют вредные эффекты (например, оптимизация возвращаемого значения по сравнению с передачей по ссылке, разворачивание цикла и т. Д. .).

16
ответ дан 7 November 2019 в 11:17
поделиться

Вот хорошая статья на эту тему: How To Go Slow

5
ответ дан 7 November 2019 в 11:17
поделиться

Ряд советов в Эффективный C ++ , Более эффективный C ++ , Эффективный STL и Стандарты кодирования C ++ находятся в этом направлении.

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

33
ответ дан 7 November 2019 в 11:17
поделиться

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

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

Этот последний маркер требует некоторого объяснения. Я не могу сказать, сколько раз я видел это:

class Foo
{
    const BigObject & bar();
};

// ... somewhere in code ...
BigObject obj = foo.bar();  // OOPS!  This creates a copy!

Правильный путь:

const BigOject &obj = foo.bar();  // does not create a copy

Эти рекомендации применимы к чему-то большему, чем умный указатель или встроенный тип. Кроме того, я настоятельно рекомендую инвестировать время в изучение профилирования вашего кода . Хороший инструмент профилирования поможет поймать расточительные операции.

-121--1069254-

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

-121--1714741-

Я бы предложил прочитать главу II («Производительность») «Жемчужины программирования» от Джона Бентли. Это не специфично для C++, но эти методы могут быть применены также в C или C++. Сайт содержит только части из книги, я рекомендую прочитать книгу.

2
ответ дан 7 November 2019 в 11:17
поделиться

Вот список, на который я ссылался в прошлом - http://www.devx.com/cplus/Article/16328/0/page/1 . Кроме того, советы по производительности C ++ в Google дают довольно много результатов.

2
ответ дан 7 November 2019 в 11:17
поделиться

Если вы действительно не уверены, что другой тип контейнера лучше, используйте ´std :: vector´. Даже если ´std :: deque, ´std :: list´, ´std :: map´ и т. Д. Кажутся более удобными вариантами, вектор превосходит их как по использованию памяти, так и по времени доступа к элементам \ итерациям.

Кроме того, предпочтительнее использовать алгоритм-член контейнера (например, ´map.equal_range (...) ´) вместо его глобальных аналогов (´std :: equal_range (begin (), end () ...) ´)

4
ответ дан 7 November 2019 в 11:17
поделиться

Вместо указателей функции используйте functors (классы с реализованным оператором operator()). Компилятор имеет более простую работу по подчёркиванию первого. Поэтому C++'s std::sort имеет тенденцию к лучшей производительности (при задании functor), чем C qsort.

11
ответ дан 7 November 2019 в 11:17
поделиться

Одной из хороших отправных точек является серия Гуру недели Саттера и книги Exceptional C ++ , выросшие из этого .

15
ответ дан 7 November 2019 в 11:17
поделиться

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

  • Pass Objects by (const) Ссылка на функции
  • Обратные объекты (Const) Ссылка при практическом
  • Убедитесь, что вы объявляете ссылочную переменную, когда вам это нужно

Эта последняя пуля требует некоторого объяснения Отказ Я не могу сказать вам, сколько раз я видел это:

class Foo
{
    const BigObject & bar();
};

// ... somewhere in code ...
BigObject obj = foo.bar();  // OOPS!  This creates a copy!

правильный путь:

const BigOject &obj = foo.bar();  // does not create a copy

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

-121--1069254-

Избегайте, как можно больше, как можно больше времени.

3
ответ дан 7 November 2019 в 11:17
поделиться

Я принял привычку предпочтить написание ++ I , а не I ++ не то, что он приносит любую повышение производительности, когда I Это int , но вещи отличаются, когда I представляет собой итератор , который может иметь сложное реализацию.

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

Кроме того, другой ресурс является Стандарты кодирования C ++: 101 правила, руководящие принципы и лучшие практики Trub Satter (Его снова) и Алексей Александреску.

Существует также более недавнее издание эффективного издания C ++ Scott Meyers C ++: Эффективное C ++: 55 специфических способов улучшения ваших программ и проектов .

Наконец, я хотел бы упомянуть подводные камни Тони Альбрехта на объекте ориентированного объектно-ориентированного программирования : не в том, что он содержит правила большого пальца, которую вы можете следовать вслепую, но это очень интересно.

2
ответ дан 7 November 2019 в 11:17
поделиться

предпочитают использовать предварительный приращение.

С INT / указателем и т. Д. Это не имеет значения.
Но с типами классов стандартный способ реализации требует создания нового объекта.

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

0
ответ дан 7 November 2019 в 11:17
поделиться

Оптимизация программного обеспечения « в C ++ » Agner Fog , как правило, одна из лучших ссылок на методы оптимизации как простым, но определенно также более продвинутым Отказ Еще одно большое преимущество состоит в том, что он свободен читать на своем сайте. (См. Ссылка на его имя для своего сайта и ссылку на заголовок бумаги для PDF).

Редактировать: Также помните, что 90% (или более) времени тратится в 10% (или меньше) кода. Таким образом, в общем оптимизирующем коде на самом деле о том, чтобы определить ваши узкие места. Дальше важно и полезно знать, что современные компиляторы будут делать оптимизацию намного лучше, чем большинство кодеров, особенно микро оптимизации, такие как задержка инициализации переменных и т. Д. Компиляторы часто чрезвычайно хорошими при оптимизации, поэтому проводят ваше время написание стабильных, надежных и простой код.

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

12
ответ дан 7 November 2019 в 11:17
поделиться
-

Используйте правильный контейнер

Контейнеры

  • Использование Вектор Для данных неизвестного размера, если вы собираетесь продолжать добавлять данные к этому. Если вы собираетесь повторно звонить push_back () , либо используйте резерв () или использовать DECKE вместо этого.
  • Если вы собираетесь добавлять / удалять данные в середине контейнера, список , вероятно, является правильным выбором.
  • Если вы собираетесь добавлять / удалять данные с обоих концов контейнера, DECE , вероятно, является правильным выбором.
  • Если вам нужно получить доступ к NT-элементу контейнера, список , вероятно, неверный выбор.
  • Если вам нужно получить доступ к NT-элементу контейнера и добавить / удалить элементы в середине, ориентирован на все три контейнера.
  • Если у вас есть возможность C ++ 0x и используем список , но вы никогда не двигаетесь назад через список, вы можете найти Forward_List . Это не будет быстрее, но он займет меньше места.

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

Ассоциативные контейнеры

  • Если у вас нет TR1, C ++ 0x, или специфичкой поставщика Unordered_foo / HASH_FOO , нет тона выбора. Используйте, какой из четырех контейнеров соответствует вашим потребностям.
  • Если у вас есть unordered_foo , используйте его вместо упорядоченной версии, если вы не заботитесь о порядке элементов, и у вас есть хорошая функция хеша для типа.

Используйте исключения, разумно

  • Не используйте исключения в вашем обычном кодовом пути. Сохраните их, когда у вас на самом деле есть исключительные обстоятельства.

Шаблоны любви

  • Шаблоны будут стоить вам во время компиляции и пространства, но прирост производительности может быть удивительным, если у вас есть расчеты, которые в противном случае были бы выполнены во время выполнения; Иногда даже что-то настолько тонкое, как нисходящее.

Избегайте Dynamic_cast

  • Dynamic_cast иногда является единственным выбором для чего-то, но часто использование Dynamic_cast может быть устранено улучшением дизайна.
  • Не заменяйте dynamic_cast с типом , а затем Static_cast .
5
ответ дан 7 November 2019 в 11:17
поделиться

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

  • Pass Objects by (Const) Ссылка на функции
  • Обратные объекты by (const) Ссылка при практичном
  • Убедитесь, что вы объявляете ссылочную переменную, когда вам это нужно

Эта последняя пуля требует некоторого объяснения Отказ Я не могу сказать вам, сколько раз я видел это:

class Foo
{
    const BigObject & bar();
};

// ... somewhere in code ...
BigObject obj = foo.bar();  // OOPS!  This creates a copy!

правильный путь:

const BigOject &obj = foo.bar();  // does not create a copy

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

26
ответ дан 7 November 2019 в 11:17
поделиться
Другие вопросы по тегам:

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