Home
Fractals
Tutorials
Books
My blog
My LinkedIn Profile

BOOKS i'm reading

Napoleon Hill Keys to Success: The 17 Principles of Personal Achievement, Napoleon Hill, ISBN: 978-0452272811
The 4-Hour Workweek: Escape 9-5, Live Anywhere, and Join the New Rich (Expanded and Updated), Timothy Ferriss, ISBN: 978-0307465351
The Fountainhead, Ayn Rand, ISBN: 0452273331
Web Hosting Canada

mailto:olivier@olivierlanglois.net

Categories: C++, tutorials

12/04/07

Permalink 09:42:06 pm, by lano1106, 566 words, 2968 views   English (CA)
Categories: C++

The RAII (Resource Acquisition Is Initialization) idiom

The name has been coined by Bjarne Stroustrup and is using the property that an object constructor and destructor will always be called at the beginning of the object existence and when it will goes out of scope. This is guaranteed by the language itself and the object will be destructed no matter how it goes out of scope. It could be by exiting a function or when the stack is unrolled by an exception been propagated out of the stack.

The RAII consists of encapsulating a resource (be it a file handle, a lock or a pointer on an object allocated on the heap) in a class. The resource acquisition will be performed in the constructor and then the C++ rules governing the lifetime of an object will take care of releasing the resource by calling the class destructor. It is to support that technique that the class template auto_ptr has been included in the standard library.

The technique has 2 purposes:

1- Simplifying code

Traditionally, it has been very error-prone to perform resource management from a function having many exit points. Suppose the following function:

void foo()
{
  // Acquire resource A
  // Do some processing
  if( error )
  {
    // release resource A
    return;
  }
  // Acquire resource B
  if( !B )
  {
    // release resource A
    return;
  }
  // Do some processing
  // Release resource A
  // Do some more processing
  // And finally, release resource B
  return;
}

Now imagine that this small game of resources tracking spans over more than a hundred lines of code and that you have dozen of resources. This is a waste of energy and chances are that there will be a resource leak in this type of code. If it is not today, it can be during the next maintenance of the function in few months or years where you will need to add another exit point in the middle of that type of function. The best way to handle this is with RAII. Once you acquire the resources, you can forget about them as they will be automatically released when the code will exit the function. As an added bonus, it will simplify the code as all the statements for releasing the resources are not needed anymore.

2- Make it easier to achieve exception safety in functions and particularly in constructors.

When an exception is thrown from a constructor of a class acquiring resources, the hard and error prone way to make sure that no resource are leaking is to place the constructor code in a try block and to manually release the acquired resource in a catch all block before rethrowing the intercepted exception. The C++ language specify that in the event of an exception during the construction, the compiler will generete code to destroy constructed base classes and data members that are objects (raw pointers on dynamically allocated memory does not count) before letting the exception escape from the constructor. Hence again, if you used RAII to encapsulate resource acquired during construction in objects, you will not need to worry about releasing them as the compiler will handle this for you.

One detail worth mentioning is the RAII is not an applicable idiom in some other OO programming languages. For instance, in Java because of its garbage collector, there is no guarantee from the language when objects will be destructed. It will just happen eventually after objects goes out of scope once the garbage collector recuperates the unused objects.

11/25/07

Permalink 05:46:39 pm, by lano1106, 366 words, 3922 views   English (CA)
Categories: C++

Optimizing C++ code for Intel processors (and possibly many others)

Pipelined processors do not like conditional branches because when conditional branch is entering in the pipeline, the processor does not know yet what will be the condition outcome but it needs to continue to fill the pipeline with new instructions. In that situation the processor will try to predict what will be the condition outcome and start filling the pipeline from its prediction. This is very costly performance wise when the processor mispredicts the condition outcome. When that happens, the processor has to flush the pipeline content and start filling it again from the branch point.

The conditional branch prediction module has 2 components. There is the branch outcome cache that will help the processor to remember what was the outcome of branches that it has encountered recently and a static branch prediction algorithm.

The static branch algorithm is very simple:

  • If the conditional branch goes further in the code, it will not be taken
  • If the conditional branch goes back in the code, it will be taken

If you read the Intel processor optimization guide, few simple guidelines are easy to apply:

1. Eliminate branches

Some conditional branches are simply useless as whether they are taken or not, it will not make any differences on the end result. 2 examples of these are:

if( i != 0 )
  i = 0;

or

if( ptr != NULL )
{
  delete ptr;
  ptr = NULL;
}

should be changed to:

i = 0;

and

delete ptr;
ptr = NULL;

It is faster to reassign the same value to a variable than conditionally assign it. The operator delete and the function free() already contain safeguards against NULL pointers and it should be quite exceptional that they are called anyway with NULL pointers.

2. Refactor if statement conditions to be true most of the time.

Here is an example:

if(error)
{
  // exceptional error handling
}
else
{
  // normal operation
}

would be faster written like:

if(!error)
{
  // normal operation
}
else
{
  // exceptional error handling
}

To conclude, these guidelines are specifically for Intel processors but since the static branch prediction algorithm used by Intel processors is widely used by other pipelined processors (PowerPC is one of them), applying them on other platforms should be beneficial as well. Also, if you are looking for other optimization techniques, you can consult these sources.

11/21/07

Permalink 10:10:47 pm, by lano1106, 271 words, 4752 views   English (CA)
Categories: C++

Undefined behavior from a pthread C++ program when calling exit()

I have done pthread programming for a while and read a couple of books on the topic too but nothing have prepared me to the undefined behavior that I have discovered the hard way.

The POSIX standard states that when the main thread exits the process, the remaining threads will be automatically terminated. What the standard does not specify is in which order the different process cleanup will occur hence if you leave the process without terminating yourself the threads, you will get undefined behavior. In my case, it was a segmentation fault.

The undefined behavior is real especially if this is a C++ program because part of the termination cleanup, there is the destruction of the program global objects. If your threads are still running and happen to use global objects, this is a sure way to a segmentation fault.

Even in fixing the problem, I have learned again something new about pthreads programming. To fix my problem, I just sent to myself the SIGINT signal that initiates the correct termination. In my first attempt, I have replaced my exit() function call with raise(SIGINT) which I have read in my UNIX programming textbook was the equivalent to kill(getpid(), SIGINT) but by doing so, the signal was never received. After some investigation, I have found in a book, that in a multithread program, raise(SIGINT) was equivalent to pthread_kill(pthread_self(),SIGINT). In my case, calling raise was doing nothing because the signal was blocked in the thread from where the call was done. Everything finally worked fine when I replaced the raise call with kill(getpid(), SIGINT).

Permalink 12:04:37 am, by lano1106, 485 words, 1836 views   English (CA)
Categories: C++

Prefer calling the prefix form of the ++ and -- operators

This is an advice that can be found in many books such as:

C++ Coding Standards, Exceptional C++, More Effective C++ or The C++ Standard Library

However, despite the abundance of literature giving this advice and explaining why, a lot of people are not aware of this. So if you are one of these persons and you are someone who is spending more time browsing the web than reading books and you have found this blog, this is for you.

At first look, statements like

++i;
i++;

seem equivalent but you have to remember that if i is an object, the increment operator is implemented with a function. Seeing the form of typical operator functions implementation should explain everything:

// Prefix version
T& T::operator++()
{
  //Perform increment
  return *this; // Return a reference on this
}

// Postfix version
T T::operator++(int)
{
  T res(*this); // Make a copy of the current value
  ++*this;      // Call the prefix version
  return res;   // Return the value by result
}

So, as you can see, most of the time the postfix increment operator is implemented in terms of the prefix one so even if you call the postfix operator, you will end up calling the prefix operator function anyway. The rest is just overhead:

  • The copy constructor will be invoked at res creation.
  • A function call will be done if operator++() is not inline
  • The copy constructor might be called a second time because res is returned by value

You'll notice that at the third point, I used 'might'. If you have a good compiler, it might be able to get rid of the construction of the return value by using a technique called the Return Value Optimization (RVO). Most compilers are able to pull off that optimization with an unnamed object (temporary object) like:

return T;

If a return statement is returning an automatic variable (local variable) declared before the return statement as it is done in the operator++(int) function, a lot fewer compilers are able to apply the RVO. Those who are able are said to have named RVO (NRVO). Visual C++ has it only since version 2005 according to this blog entry. GCC supports it since version 3.1 according to this Boost mailing list archive entry.

To conclude, it should now be obvious that unless you absolutely need the postfix increment semantic, you should use the prefix version. This should represents 99% of the increments in a program since usually, they stand alone in their own statement and the return value is just not used at all. This is usually what happens in code using STL containers iterators. One could argue that it does not make a perceptable difference performance wise in a program. Maybe but why choosing the slowest option when both ways are equally easy to write? Herb Sutter and Andrei Alexandrescu think the same and they give the excellent advice (Don't pessimize prematurely) in their book C++ Coding Standards.

11/19/07

Permalink 11:38:11 pm, by lano1106, 575 words, 6664 views   English (CA)
Categories: C++

How to remove dynamically allocated pointers from STL set

Before clearing or destructing a STL container containing dynamically allocated pointers, it is important to delete the pointers or else, you are going to leak memory and resources (See item 7 in Effective STL). The usual way to this is:

for( vector<MyClass*>::iterator it = v.begin(),
     e = v.end(); it != e; ++it )
{
    delete *it;
}
v.clear();

There is a small twist with sets. This code would be fine with a set using its default compare function but since sorting pointers with their values is not very useful, most of the time, such containers are configured with a custom compare function that dereference the pointers to perform its comparison. The standard does not specify which set methods use the compare function and which are not. So it is looking for trouble to free the memory and keep the pointers on it in the set and at best your set will be in an invalid state.

The easy way is to store boost::smart_ptr<MyClass*> into the set. All you have to do is to clear the set and the smart pointers will take care of deallocating the memory. My opinion, however, is that this solution is like using a machine gun to kill a mosquito. The real purpose of smart pointers is for dealing with situations where the pointers ownership is fuzzy. If you know that it is safe without any doubt to delete the pointers in your container when you want to clear it, you should not be using smart pointers.

Another option is to use boost::ptr_set but since I am not very familiar with this class, this is not something I will recommend.

The best solution that I have seen is simply doing this:

typedef std::set<MyClass*,
                 CompFuncThatDerefencePointers> MySet;
 
for( MySet::iterator it = s.begin(),
     e = s.end(); it != e; )
{
    MyClass *p = *it;
    s.erase(it++);
    delete p;
}

There are 2 more details that I want to discuss. Some STL containers (such as set and map) erase() method signature is

void erase(iterator it);

and some other containers (list and vector) have

iterator erase(iterator it);

The second signature makes sense for containers that upon insertion or removal of elements invalidates all iterators on it but I have no idea why list has its erase returning an iterator. If you think that you might switch from a list to an associative container, you might want to erase elements from the list with

l.erase(iter++);

to keep your code compatible with the associative containers interface. As I am writing, I think that the STL designers decided to make the list erase signature compatible with the vector erase because they considered that this was the most likely switch if you had to change your container strategy.

The other important point that I wanted to mention is that my recommendation to explicitly clear the pointers rather than using boost::smart_ptr assumes that your container is a data member of a class and that you are using the RAII idiom. That is that you are deleting the container elements memory in the class destructor. This is to be sure that your code is exception-safe. If your container is an automatic variable in a function, then this might be an appropriate situation to use boost::smart_ptr because if you do not and an exception is thrown before your container clearing code is executed, you will leak memory.

<< Previous Page :: Next Page >>

Olivier Langlois's blog

I want you to find in this blog informations about C++ programming that I had a hard time to find in the first place on the web.

< Previous | Next >

March 2024
Sun Mon Tue Wed Thu Fri Sat
 << <   > >>
          1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31            

Search

Custom Search

Misc

XML Feeds

What is RSS?

Who's Online?

  • Guest Users: 2

powered by
b2evolution