|
Location: Desktop development - C/C++ License: The Intelliproject Open License (IPOL) C++ Optimization TechniquesPosted by cocoaThis article describe some strategies used to optimize your c++ applications speed. |
Skill: BeginnerPosted: 27/09/2010Views: 666Rating: 4.00 /5Popularity: 0.00 |
| Sign Up to vote for this article |
This article describes some techniques and strategies which can be used to optimize your c++ applications.
These techniques cover the following chapters:
Constructors and Destructors
Virtual functions
Return Value
Temporary Objects
C++ normally passes arguments by value (as C does) . For example:
K a; void foo(K x);
The call foo(a) copies argument a to x before transferring control to foo. The parameter x will be placed on the function stack. The function parameters are pushed on the stack before the function is called and the parameters are pushed from right to left.
If type K is a built-in type such as int, double,float and so on , passing by value is inexpensive - as inexpensive as it is in C.
However, if K is a class type, passing by value copies a to x by invoking the copy constructor of the class. Calling the copy constructor generate in most of cases an unnecessary overhead and can be very expensive.
C++ offers several ways to avoid this case. In C and C++ you can pass parameters by address. To do this, you can declare foo as:
void foo(K *x);
For large objects, passing by address is clearly faster that passing by value. Unfortunately, you must then write the call as foo(&a), which changes its appearance. It also changes the semantics of the call by making it possible for foo to change the value of a. Using the const qualifier you ensure that foo does not change the value of its actual argument.
void foo(K const *x);
For objects of modest size (8 to 16 bytes), it isn't always clear that passing by address will actually be faster than passing by value. Switching between pass- by-address and pass-by-value poses a maintenance problem. Not only must you change the function declarations, as in:
void foo(K x); => void foo(K const *x);
but you must also change all the function calls, as in:
foo(a); => foo(&a);
The alternative is to declare foo using a reference-to-const parameter, as in:
void foo(K const &x);
This lets you write the call as foo(a) (like passing by value), but keeps the speed of passing by address. Also, the const qualifier ensures that foo can't change the value of its argument.
Passing by reference-to-const may have a surprising cost. When passing by reference- to-const the compiler may construct a temporary object holding a copy of the argument.
Temporary objects are unnamed objects created on the stack by the compiler. They are created and used during reference initialization and during evaluation of expressions including standard type conversions, argument passing, function returns, and evaluation of the throw expression.
The alternative is to pass a reference-to-non-const:
void foo(K &x);
In that case the compile will not create any temporary object. But your function is allowed to change the content of your passed parameter.
The performance of constructors and destructors in most cases are poor due to the fact that an object's constructor (destructor) may call the constructors (destructors) of member objects and parent objects. This can result in constructors (destructors) that take a long time to execute, especially with objects in complex hierarchies or objects that contain several member objects.
Use the following hints to make your constructors and destructors more efficiently:
ESI, EDI, EBX, and EBP are saved on the stack.EAX registerESI, EDI, EBX, and EBP are restored from the stack. Virtual functions affect performance in 3 main ways:
vptr table (a table of pointers to its member functions).To avoid the overhead of virtual functions, you can use a template class in place of inheritance. A template class does not use the vptr table because the type of class is known at compile-time instead of having to be determined at run-time. Also, the non-virtual methods in a template class can be inlined.
The cost of using virtual functions is usually not a factor in calling methods that take a long time to execute since the call overhead is dominated by the method itself. In smaller methods, for example accessor methods, the cost of virtual functions is more important.
Returning an object of built-in type from a function usually carries little to no overhead, since the object typically fits in a CPU register.Returning a larger object of class type may require more expensive copying from one memory location to another. To achieve this, an implementation may create a hidden object in the caller's stack frame, and pass the address of this object to the function. The function's return value is then copied into the hidden object since constructing this object takes time, you should try to avoid this it if possible.
There are several ways to accomplish this:
As I have described above, temporary objects are unnamed objects created on the stack by the compiler. They are created in various situations like:
When you pass an object to a method by value the compiler will create an temporary object. To avoid this pass by address or pass by reference. Read "Parameter passing" chapter.
Compilers may create a temporary object in assignment of an object. For example, a constructor that takes an int as an argument may be assigned an int. The compiler will create a temporary object using the int as the parameter and then call the assignment operator on the object. You can prevent the compiler from doing this behind your back by using the explicit keyword in the declaration of the constructor.
When objects are returned by value, temporaries are often used. Read "Return Value" section for more on this.
Temporaries can be avoided by using <op>= operators. For example, the code:
a = b + c;
could be written as:
a=b;
a+=c;
When a function is declared inline, the function is expanded at the compile time. The function is not treated as a separate unit like other normal functions. But a compiler is free to decide, if a function qualifies to be an inline function. If the inline function is found to have larger chunk of code, it will not be treated as an inline function.
Inlining is one of the easiest optimizations to use in C++ and it can result in the most dramatic improvements in execution speed.
Advantages
Disadvanteges
The main thing to know when using inlining is when you should inline a method and when you shouldn't inline:
This article, along with any associated source code and files, is licensed under The Intelliproject Open License (IPOL)
| cocoa
| Location: |
Sign up to post message on the article message board!