Кто-то мог указать на меня на статью или записать некоторые подсказки прямо здесь о некоторых привычках программирования на C++, которые обычно допустимы (никакие реальные недостатки), и улучшает производительность? Я не имею в виду шаблоны программирования и сложность алгоритма - мне нужны мелочи как то, как Вы определяете свои функции, вещи/к избегают в циклах, что выделить на стеке, что на "куче", и так далее.
Это не о создании конкретного программного обеспечения быстрее, также это не о том, как создать чистую разработку программного обеспечения, а скорее привычки программирования, что - если Вы всегда применяете их, Вы сделаете свой код довольно немного быстрее, чем немного медленнее.
] Здесь уже много хороших предложений. [
] [] Один из лучших способов вжиться в хорошие привычки - это навязать их себе. За это я люблю PC-Lint. PC-Lint на самом деле обеспечит соблюдение правил С++ и более эффективных С++ Скотта Мейера. Кроме того, соблюдение правил Lint, как правило, приводит к тому, что код становится проще в обслуживании, меньше подвержен ошибкам и чище. Только не сходите с ума, если вы понимаете, что lint часто генерирует больше вывода, чем у вас есть в исходном коде; однажды я работал над проектом с исходным кодом 150MB и 1.8GB сообщений Lint.[
].][][]Эта страница суммирует все, что вы должны знать об оптимизации на Си++ (будь то во время или после написания программного обеспечения).[][] Это действительно хороший совет и очень познавательно -- и может быть использовано в качестве полезного напоминания на этапе оптимизации в проекте.[
] []Она немного старая, так что вы также должны знать, какие оптимизации уже сделаны вашим компилятором (например, NRVO). [
] []Кроме того, чтение уже процитированных стандартов кодирования Effective C++, More Effective C++, Effective STL и C++ Coding Standards также важно, так как они многое объясняют о том, что происходит в языке и в STL, позволяя лучше оптимизировать конкретный случай, используя лучшее понимание того, что именно происходит.[
].] Мне нравится этот вопрос, потому что он задает некоторые "хорошие привычки". Я обнаружил, что некоторые вещи, которые желательны при программировании, изначально являются рутинной работой, но становятся приемлемыми и даже легкими, как только они становятся привычками. [
] [] Одним из примеров всегда является использование умных указателей вместо необработанных указателей для контроля времени жизни кучи памяти. Другой, конечно же, связан с развитием привычки всегда использовать RAII для получения и освобождения ресурсов. Другой - всегда использовать исключения для обработки ошибок.
Эти три правила, как правило, упрощают код, тем самым делая его меньше и быстрее, а также проще для понимания. [
][
] Можно также сделать геттеры и сеттеры неявно встроенными; всегда полностью использовать списки инициализаторов в конструкторах; и всегда использовать функции find и другие связанные с ними функции, которые предоставляются в std-библиотеке, вместо того, чтобы создавать собственные циклы. [
] []Не особенно C++, но часто стоит избегать копирования данных. В многолетних программах с большим количеством выделяемой памяти может быть целесообразно рассматривать выделение памяти как основную часть конструкции, так что используемая память поступает из повторно используемых пулов, хотя это не всегда достаточно распространенная вещь, чтобы считаться достойной формирования привычки. [
] [] И еще одно - не копируйте код из одного места в другое, если вам нужна функциональность - используйте функцию. Это уменьшает размер кода и облегчает оптимизацию всех мест, использующих данную функциональность.[
].]Шаблоны! Использование шаблонов может сократить объем кода, так как можно иметь класс или функцию/метод, которые могут быть многократно использованы со многими типами данных.[
] []Рассмотрим следующее:[
] [#include <string>
using std::basic_string;
template <class T>
void CreateString(basic_string<T> s)
{
//...
}
]
[]Основная_строка может состоять из char, wchar_t, unsigned char или unsigned wchar_t.[
] []Шаблоны также могут быть использованы для множества различных вещей, таких как трейты, специализация класса, или даже использоваться для передачи значения int в класс![
]] Из Вашего вопроса кажется, что Вы уже знаете о философии "преждевременная оптимизация - это зло", так что проповедовать об этом я не буду. :)[
] []Современные компиляторы уже достаточно умны в микро-оптимизации. Если вы будете слишком сильно стараться, то часто сможете сделать все медленнее, чем в исходном простом коде.[
] []Для небольших "оптимизаций" можно безопасно обойтись без раздумий, что не сильно влияет на читабельность/сохранение кода, посмотрите раздел "Premature Pessimization" книги []C++ Coding Standards[] by Sutter & Alexandrescu.[
] []Для более детальных техник оптимизации посмотрите []Efficient C++[] by Bulka & Mayhew. Используйте только тогда, когда это оправдано профилированием![
] []Для хорошей общей практики программирования на С++ смотрите:[
] []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, возможно, лучше не встраивать его, не важно насколько он маленький. Это связано с тем, что реализация встроенных функций должна быть видна другим модулям/классам. Если вы что-то измените в этой встроенной функции/методе, то другие модули, на которые она ссылается, должны быть перекомпилированы.[
] []Когда я только начинал программировать, я пытался микро-оптимизировать все (это был инженер-электрик во мне). Какая пустая трата времени![
] []Если вы встраиваетесь во встраиваемые системы, то все меняется и вы не можете воспринимать память как само собой разумеющееся. Но это еще одна целая банка червей.[
]] Почему об этом до сих пор никто не упоминал? Почему всем нравится бедняжка [] ++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[
] вы можете выиграть не очень много, но передача []больших [] объектов вроде этого, может сэкономить вам довольно много вычислительной мощности, так как вы избегаете избыточного копирования. А также может избавить вас от пары ошибок, если вы забыли реализовать свой конструктор копирования.[
Лучший способ улучшить эти навыки - это читать книги и статьи, но я могу помочь вам некоторыми советами:
Удивительно, как можно увеличить производительность. Для меня 1500 раз за тяжелое вычислительное приложение. Не более грубого носа, а более похожих структур данных, написанных в основном программном пакете.
Я бы не стал зацикливаться на этом, как преинкремент над постом. Это даёт экономию только в определённых (неважных) случаях, и большинство из того, что упоминается, это похожие вещи, которые могут отскребать лишний 1% здесь и там время от времени, но обычно не стоят того, чтобы беспокоиться.
Несколько моих любимых раздражений:
if (a && b)
, если b с большей вероятностью будет ложным, поместите его первым, чтобы сохранить оценку a. Есть много других «вредных привычек», о которых я не буду упоминать, потому что на практике современные компиляторы / оптимизаторы устраняют вредные эффекты (например, оптимизация возвращаемого значения по сравнению с передачей по ссылке, разворачивание цикла и т. Д. .).
Ряд советов в Эффективный C ++ , Более эффективный C ++ , Эффективный STL и Стандарты кодирования C ++ находятся в этом направлении.
Простой пример такого совета: по возможности используйте преинкремент (++ i), а не постинкремент (i ++). Это особенно важно для итераторов, поскольку постинкремент включает в себя копирование итератора. Ваш оптимизатор может отменить это, но вместо этого писать преинкремент не нужно, так зачем рисковать?
Если я правильно вас понимаю, вы спрашиваете о том, чтобы избежать Преждевременной пессимизации , хорошего дополнения к предотвращению преждевременной оптимизации. # 1, чего следует избегать, исходя из моего опыта, это не копировать большие объекты, когда это возможно. Сюда входит:
Этот последний маркер требует некоторого объяснения. Я не могу сказать, сколько раз я видел это:
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++. Сайт содержит только части из книги, я рекомендую прочитать книгу.
Вот список, на который я ссылался в прошлом - http://www.devx.com/cplus/Article/16328/0/page/1 . Кроме того, советы по производительности C ++ в Google дают довольно много результатов.
Если вы действительно не уверены, что другой тип контейнера лучше, используйте ´std :: vector´. Даже если ´std :: deque, ´std :: list´, ´std :: map´ и т. Д. Кажутся более удобными вариантами, вектор превосходит их как по использованию памяти, так и по времени доступа к элементам \ итерациям.
Кроме того, предпочтительнее использовать алгоритм-член контейнера (например, ´map.equal_range (...) ´) вместо его глобальных аналогов (´std :: equal_range (begin (), end () ...) ´)
Вместо указателей функции используйте functors (классы с реализованным оператором operator()
). Компилятор имеет более простую работу по подчёркиванию первого. Поэтому C++'s std::sort
имеет тенденцию к лучшей производительности (при задании functor), чем C qsort
.
Одной из хороших отправных точек является серия Гуру недели Саттера и книги Exceptional C ++ , выросшие из этого .
Если я вас правильно понимаю, вы спрашиваете об избежании преждевременной пессимизации , хорошего дополнения к избежанию преждевременной оптимизации. То, что следует избегать, основанная на моем опыте, не копирует большие объекты, когда это возможно. Это включает в себя:
Эта последняя пуля требует некоторого объяснения Отказ Я не могу сказать вам, сколько раз я видел это:
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-Избегайте, как можно больше, как можно больше времени.
Я принял привычку предпочтить написание ++ I
, а не I ++
не то, что он приносит любую повышение производительности, когда I
Это int
, но вещи отличаются, когда I
представляет собой итератор
, который может иметь сложное реализацию.
Тогда давайте скажем, вы пойдете с языка программирования C, потерять привычку объявить все ваши переменные в начале функции: объявить ваши переменные, когда они необходимы в функциональном потоке, поскольку функция может содержать ранние возврата
Заявления до некоторых переменных, которые были инициализированы в начале, эффективно используются.
Кроме того, другой ресурс является Стандарты кодирования C ++: 101 правила, руководящие принципы и лучшие практики Trub Satter (Его снова) и Алексей Александреску.
Существует также более недавнее издание эффективного издания C ++ Scott Meyers C ++: Эффективное C ++: 55 специфических способов улучшения ваших программ и проектов .
Наконец, я хотел бы упомянуть подводные камни Тони Альбрехта на объекте ориентированного объектно-ориентированного программирования : не в том, что он содержит правила большого пальца, которую вы можете следовать вслепую, но это очень интересно.
предпочитают использовать предварительный приращение.
С INT / указателем и т. Д. Это не имеет значения.
Но с типами классов стандартный способ реализации требует создания нового объекта.
Так что предпочитаю предварительный приращение. На всякий случай в более позднем моменте типы изменяются.
Тогда вам не нужно будет изменять код, чтобы справиться.
Оптимизация программного обеспечения « в C ++ » Agner Fog , как правило, одна из лучших ссылок на методы оптимизации как простым, но определенно также более продвинутым Отказ Еще одно большое преимущество состоит в том, что он свободен читать на своем сайте. (См. Ссылка на его имя для своего сайта и ссылку на заголовок бумаги для PDF).
Редактировать: Также помните, что 90% (или более) времени тратится в 10% (или меньше) кода. Таким образом, в общем оптимизирующем коде на самом деле о том, чтобы определить ваши узкие места. Дальше важно и полезно знать, что современные компиляторы будут делать оптимизацию намного лучше, чем большинство кодеров, особенно микро оптимизации, такие как задержка инициализации переменных и т. Д. Компиляторы часто чрезвычайно хорошими при оптимизации, поэтому проводят ваше время написание стабильных, надежных и простой код.
Я утверждаю, что он платит, чтобы сосредоточиться на выборе алгоритма, чем на микрооптизациях, по крайней мере, по большей части.
Вектор
Для данных неизвестного размера, если вы собираетесь продолжать добавлять данные к этому. Если вы собираетесь повторно звонить push_back ()
, либо используйте резерв ()
или использовать DECKE
вместо этого. список
, вероятно, является правильным выбором. DECE
, вероятно, является правильным выбором. список
, вероятно, неверный выбор.
, но вы никогда не двигаетесь назад через список, вы можете найти Forward_List
. Это не будет быстрее, но он займет меньше места. Обратите внимание, что этот совет становится более применимым чем больше контейнер. Для более мелких контейнеров вектор
может всегда быть правильным выбором просто из-за нижних постоянных факторов. Когда сомневаетесь, ориентир.
Unordered_foo
/ HASH_FOO
, нет тона выбора. Используйте, какой из четырех контейнеров соответствует вашим потребностям. unordered_foo
, используйте его вместо упорядоченной версии, если вы не заботитесь о порядке элементов, и у вас есть хорошая функция хеша для типа. Dynamic_cast
Dynamic_cast
иногда является единственным выбором для чего-то, но часто использование Dynamic_cast
может быть устранено улучшением дизайна. dynamic_cast
с типом
, а затем Static_cast
. Если я Понимаю вас правильно, вы спрашиваете о том, чтобы избежать преждевременной пессимизации , хорошего дополнения к избежанию преждевременной оптимизации. То, что следует избегать, основанная на моем опыте, не копирует большие объекты, когда это возможно. Это включает в себя:
Эта последняя пуля требует некоторого объяснения Отказ Я не могу сказать вам, сколько раз я видел это:
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
Эти рекомендации относятся к чему больше, чем умного указателя или встроенного типа. Кроме того, я настоятельно рекомендую инвестировать время обучения на профиля вашего кода . Хороший профилированный инструмент поможет поймать расточительные операции.