General C ++ Performance Tips

Can someone point me to an article or write some tips right here about some C ++ programming habits that are usually valid (no real flaws) and improve performance? I do not mean programming patterns and the complexity of the algorithm. I need such little things as how you define your functions, what to do / avoid in loops, what to allocate on the stack, on the heap, etc.

This is not about speeding up the development of specific software, nor about how to create a clean software design, but rather about programming habits, which - if you always use them, you will make your code a little faster than a little slower.

Thank:)

+41
c ++
Jan 08 '10 at 19:37
source share
24 answers

Some tips on Effective C ++ , More Effective C ++ , Effective STL, and C ++ Coding Standards this line.

A simple example of such a tip: use preincrement (++ i) rather than post-increment (i ++) whenever possible. This is especially important when using iterators, since post-instinct involves copying an iterator. The optimizer may be able to undo this, but instead do not need to write an additional entry, so why take the risk?

+27
Jan 08 '10 at 19:47
source share

If I understand you correctly, you are asking about avoiding Premature Pessimization , which is a good complement to preventing premature optimization. # 1, to avoid, based on my experience, do not copy large objects when possible. It includes:

  • pass objects by (const) function reference
  • return objects by (constant) link whenever practical
  • make sure you specify the reference variable when you need it.

This last bullet requires some explanation. I can’t say how many times I saw this:

class Foo { const BigObject & bar(); }; // ... somewhere in code ... BigObject obj = foo.bar(); // OOPS! This creates a copy! 

The right way:

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

These recommendations apply to anything that exceeds the smart pointer or built-in type. In addition, I highly recommend spending time learning the profile of your code . A good profiling tool will help catch wasteful operations.

+24
Jan 08 '10 at 19:48
source share

One good starting point is Sutter Guru of the week "and" Exceptional C ++ Books ", which grew out of this.

+14
Jan 08 '10 at 19:45
source share

A few of my pets:

  • Do not declare (in fact, define) object variables before using / initializing them (as in C). This requires that the AND constructor operator functions also be performed for complex objects, which can be expensive.
  • Prefer pre-increment for subsequent increment. This will only be relevant for iterators and custom types with overloaded operators.
  • Use the smallest primitive types. Do not use long int to store a value in the range 0..5. This will reduce overall memory usage, improve locality, and therefore overall performance.
  • Use heap memory (dynamic allocation) only if necessary. Many C ++ programmers use the default heap. Dynamic allocations and waivers are expensive.
  • Minimize the use of time series (especially in row-based processing). Stroustrup is a good technique for determining the logical equivalent of higher-order three-dimensional and arithmetic operators in the "C ++ programming language".
  • Know your compiler / linker options. You also know which ones cause unusual behavior. This significantly affects runtime performance.
  • Know the performance / functionality tradeoffs of STL containers (for example, don't insert them often into a vector, use a list).
  • Do not initialize variables, objects, containers, etc., when they are unconditionally assigned.
  • Consider the procedure for evaluating composite conditional numbers. For example, if if (a && b) , if b is more likely to be false, put it first to save the estimate.

There are many other "bad habits" that I will not mention, because in practice modern compilers / optimizers eliminate harmful effects (for example, optimizing the return value compared to passing by reference, disabling the loop, etc. ..).

+14
Jan 08 '10 at 20:10
source share

" Software optimization in C ++ Agner Fog , as a rule, is one of the best links to optimization methods, both simple and more advanced. Another great advantage is that it can be freely read on your website. ( See Link to his name for your site and link to paper name for pdf).

Edit: Also remember that 90% (or more) of the time spent on 10% (or less) of the code. So overall, optimizing the code is really related to your bottlenecks. In addition, it is important and useful to know that modern compilers will optimize much better than most coders, especially microoptimizations, such as delaying the initialization of variables, etc. Compilers are often very good at optimizing, so spend your time creating stable, reliable, and simple code.

I would say that he plans to focus more on choosing an algorithm than on micro-optimization, at least for the most part.

+11
Jan 08 '10 at 19:52
source share

Use functors (classes with operator() implemented) instead of function pointers. The compiler has an easier job nested in the first. Therefore, C ++ std::sort tends to work better (when defining a functor) than C qsort .

+11
Jan 08 '10 at 19:55
source share

On your question, it seems that you already know about the philosophy of “premature optimization of evil,” so I will not preach about it. :)

Modern compilers are already pretty smart at micro optimization for you. If you try too hard, you can often do something slower than the original straightforward code.

For small "optimizations" you can safely and without hesitation, and this does not affect the readability / portability of the code, check the section "Premature pessimization" in the book "C ++ Coding Standards" by Sutter and Alexandrescu.

For more optimization methods, check out Efficient C ++ from Bulka and Mayhew. Use only if warranted by profiling!

For good general C ++ programming rules, check:

  • C ++ coding standards from Sutter and Alexandrescu (must be IMHO)
  • Efficient C ++ / STL Series by Scott Meyers
  • Exceptional C ++ Series from Herb Sutter

Above my head, one good common practice is to transfer heavy objects by reference, not copies. For example:

 // 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; } 

For a small object, such as a complex number or a two-dimensional (x, y) point, the function will most likely work faster with the object transferred by the copy.

When it comes to objects with a fixed size and average weight, it is not so clear if the function will work faster with a copy or link to the object. Only profiling will tell. Usually I just pass the const link (if the function doesn't need a local copy) and worry about it if the profiling tells me.

Some will say that you can embed methods in a small class without thinking. This can give you better performance at runtime, but it can also extend compilation time if you have a large number of attachments. If the class method is part of the library API, it is best not to include it, no matter how small it is. This is due to the fact that the implementation of built-in functions should be visible to other modules / classes. If you change something in this built-in function / method, then the other modules that reference it must be compiled.

When I first started programming, I would still try to optimize everything (it was an electrical engineer in me). What a waste of time!

If you are in embedded systems, then everything changes, and you cannot take memory for granted. But this is another whole can of worms.

+8
Jan 08 '10 at
source share

Here is a good related article: How To Go Slow

+5
Jan 08 '10 at 19:54
source share

Use the correct container

Sequence containers

  • Do not use vector for data of unknown size if you intend to add data to it. If you intend to call push_back() again, use reserve() or use deque instead.
  • If you are going to add / remove data in the middle of the container, list is probably the right choice.
  • If you are going to add / remove data from both ends of the container, the right choice may be the right one. deque .
  • If you need to access the nth element of a container, list is probably the wrong choice.
  • If you need both access to the nth element of the container and add / remove elements in the middle, check all three containers.
  • If you have the C ++ 0x feature and use list , but you never move backward through the list, you can find forward_list more to your liking. It will not be faster, but it will take up less space.

Please note that this tip becomes more applicable the larger the container. For small containers, vector can always be the right choice simply because of lower constant factors. If in doubt, a guideline.

Associative containers

  • If you don't have TR1, C ++ 0x, or the provider-specific unordered_foo / hash_foo , then there is no choice. Use any of the four containers that suit your needs.
  • If you have unordered_foo , use it instead of the ordered version, if you don't need the order of the elements, and you have a good hash function for this type.

Use exceptions wisely

  • Do not use exceptions in your regular code. Save them if you really have exceptional circumstances.

Love patterns

  • Templates will cost you at compile time and in space, but performance gains can be amazing if you have calculations that would otherwise be performed at runtime; sometimes even something as subtle as low.

Avoid dynamic_cast

  • dynamic_cast sometimes the only choice for something, but often the use of dynamic_cast can be eliminated by improving the design.
  • Do not replace dynamic_cast with typeid and then with static_cast .
+5
Jan 08 '10 at
source share

Templates! Using templates can reduce the amount of code because you can have a class or function / method that can be reused by many data types.

Consider the following:

 #include <string> using std::basic_string; template <class T> void CreateString(basic_string<T> s) { //... } 

The base_string can consist of char, wchar_t, unsigned char or unsigned wchar_t.

Templates can also be used to create several objects, such as traits, class specialization, or even used to pass int values ​​to a class!

+4
Jan 08 '10 at 20:05
source share

If you are really sure that another type of container is better, use 'std :: vector'. Even if 'std :: deque,' std :: list ',' std :: map ', etc. It seems to be a more convenient choice, the vector surpasses them both in memory use and in access to the element \ iteration.

In addition, it is preferable to use a container member algorithm (for example, the apap.equal_range (...) 'file) instead of its global mappings (' std :: equal_range (begin (), end () ...) ')

+4
Jan 08 '10 at 20:11
source share

I like this question because it asks for some “good habits”. I found that some of the things that are desirable in programming are initially a chorus, but they become acceptable and even easy when they become habits.

One example always uses smart pointers instead of raw pointers to control the lifetime of the memory heap. Another, of course, is associated with the habit of always using RAII to collect and release resources. Another always uses exceptions to handle errors. These three tend to simplify the code, thereby decreasing it both faster and easier to understand.

You can also make getters and setters implicitly inline; always make full use of initializer lists in constructors; and always use the find function and other related functions that are provided in the std library, instead of creating your own loops.

Not specifically C ++, but you should often avoid copying data. In long-term programs with a large amount of memory allocation, it may be advisable to consider memory allocation as the main part of the design, so that the memory you use comes from pools that are reused, although this is not necessarily a common thing to be considered worthy of forming a habit.

One more thing - do not copy the code from one place to another, if you need functionality - use the function. This reduces the size of the code and simplifies the optimization of all places that use this functionality.

+4
Jan 08 '10 at 20:44
source share

Avoid reusing the same dataset as soon as possible.

+3
Jan 08 '10 at 19:51
source share

Here is the list that I mentioned in the past - http://www.devx.com/cplus/Article/16328/0/page/1 . In addition, performance tips for Googling C ++ give quite a bit.

+2
Jan 08 '10 at 19:47
source share

I'm used to prefer writing ++i rather than i++ rather than that it improves performance when i is int , but things change when i is an iterator , which can have a complicated implementation.

Then let's say that you came from the C programming language, you lose the habit of declaring all your variables at the beginning of the function: declare your variables when they are needed in the function stream, since the function may contain early return expressions before some variables that were initialized in the beginning.

In addition, another resource C ++ Coding Standards: 101 Rules, Recommendations and Recommendations from Herb Sutter (him again) and Alexey Alexandrescu.

There is also a more up-to-date edition of Scott Meyers' Effective C ++: Effective C ++: 55 specific ways to improve your programs and projects .

Finally, I would like to mention Tony Albrecht's Object Oriented Programming Traps : not only does it contain rules of thumb, you can follow blindly but it is very interesting to read.

+2
Jan 08 '10 at 19:48
source share

I would suggest reading Chapter II ("Productivity") "Programming Pearls" by John Bentley. This is not C ++, but these methods can be applied in C or C ++. The site has only parts from the book, I recommend reading the book.

+2
Jan 08 '10 at 19:50
source share

On this page, summarize everything you need to know about C ++ optimization (whether during or after writing software). This is really good advice and very personal - and can be used as a useful reminder in the optimization phase of the project.

This is a bit outdated, so you should also know which optimizations your compiler is already doing (e.g. NRVO).

In addition to this, it is also important to read effective C ++, more efficient C ++, effective STL and C ++ coding standards that have already been mentioned, because it explains a lot of what is happening in the language and in the STL, which allows you to better optimize your case using a better understanding of what happens exactly.

+2
Jan 08 '10 at 20:55
source share

There are already a lot of good suggestions.

One of the best ways to imbue good habits is to force them to yourself. For this, I love PC-Lint. PC-Lint will actually provide efficient C ++ and more efficient Scott Meyer C ++ rules. Compliance with Lint rules also tends to simplify maintenance, reduce error susceptibility, and cleaner code. Just don't go crazy when you realize that lint often generates more output than the source code; I once worked on a project with 150 MB of source code and 1.8 GB of Lint messages.

+1
Jan 08
source share
  • Avoid memory fragmentation.
  • Compatible memory.
  • SIMD instructions.
  • Keyless multithreading.
  • Use the right acceleration trees like kd-tree, tree tree, octree, quadtree etc. 5a. Define them in ways that allow the first three (i.e., make the nodes all in one block).
  • embedding. The lowest hanging, but quite tasty fruit.

The productivity gains you can get in this way are amazing. For me, 1,500 times to calculate a heavy application. Not too coarse, but over similar data structures written in the main software package.

I would not bother to get stuck as a preincrement over the post. This only gives savings on certificates (unimportant) cases, and most of the similar things mentioned that can scrape off the extra 1% here and there from time to time, but usually do not bother.

+1
Jan 09 '10 at
source share

Prefers to use pre-increment.

With int / pointer etc. it does not matter.
But with class types, the standard implementation method requires the creation of a new object.

So prefer pre-increment. Just in case, in later cases, the types are changed.
Then you will not need to change the code to handle it.

0
Jan 08 '10 at 19:47
source share

The best way to improve these skills is to read books and articles, but I can help you with some tips:

  • 1- Accept objects by reference and primitive or pointer types by value, but use the object pointer if the function stores a link or a pointer to an object.
  • 2- Do not use MACROS to declare constants -> use static const.
  • 3 Always execute a virtual destructor if your class can be a subclass.
0
Jan 08 '10 at 19:58
source share
  • Avoid multiple inheritance.
  • Use virtual machines when you need them, not just for fun
  • Use collection template classes only when it hurts not for
0
Jan 08
source share

Why has no one mentioned this so far? Why is every person in poor little ++i ?

One of the best things you can easily do so as not to pessimize the code:

Effective C ++ Scott Meyers, Position 20:

Prefer pass-by-reference-to-const value for pass-on value

Example:

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

In the case of a short std::string you may not win much, but passing large objects like this can save you quite a bit of processing power, since you avoid excessive copying. And it can also save you from an error or two if you forgot to implement your copy constructor.

0
Jan 08
source share

This will have very good methods for general C ++ optimization:

http://www.tantalon.com/pete/cppopt/main.htm

Use the profiler to find out which part of the application is slow, and then use the optimization methods.

I used valgrind with the callgrind tool for the purpose of profiling, and it will give you what lines cost how much.

valgrind --tool = callgrind

0
Jun 14 '17 at 16:14
source share



All Articles