Showing posts with label RAII. Show all posts
Showing posts with label RAII. Show all posts

2010-04-26

Exit strategy: Single exit point is less readable

Single exit point produces the pyramid of code syndrome.

bool solve2
    (
        double a, double b, double c
        , double& x1, double& x2
    )
{
    bool ret = true;
    if(a!=0) {
        double det = b*b - 4*a*c;
        if(det>=0) {
            ret = true;
            det = sqrt(det);
            double p2a = 1 / (2*a);
            x1 = (-b - det) * p2a;
            x2 = (-b + det) * p2a;
            // The top of the code pyramid
        } else
            ret = false;
    } else
        ret = false;
    return ret;
}

Using early returns helps keeping the error handing and productive code apart.

bool solve2
    (
        double a, double b, double c
        , double& x1, double& x2
    )
{
    // Checking for trivial errors and trivial solutions
    if(a==0)
        return false;
    double det = b*b - 4*a*c;
    if(det<0)
        return false;
    // Main part without pyramid
    det = sqrt(det);
    double p2a = 1 / (2*a);
    x1 = (-b - det) * p2a;
    x2 = (-b + det) * p2a;
    return true;
}

Note: This function solves the quadratic equation (a * x^2 + b * x + c = 0).

Note: You have to be careful with the multiple exit point style if you are acquiring resources (opening files, allocating memory, ...), because it can lead to leaks. Avoiding these kind of leaks is simpler in C++ than in most languages, because the lifetime of acquisitions can be bound to scope.

Yes, it is C. Smaller scope better scope

Once upon a time there lived a paradigm (sorry, that is an ugly word, but I don't know better) which told the programmer to declare all the variables at the beginning of the function. This paradigm was enforced by the compiler in Pascal, C and many other languages. You can guess. It was easier to write compilers that way. Then came the new winds with C++ (maybe it wasn't the first) which introduced RAII (Resource acquisition is initialization) which gave us three brand new concepts at once.
  • Variable scoping
  • Lifecycle management by scope (calling destructor when execution reaches the end of it's scope)
  • Bounding lifecycle of a variable to an object
Many may not know but since C99 the first is also available in C. A trivial example of it is the in-place declaration of iterator in for.
for(int i=0; i<10; ++i){ printf("%d^2 = %d\n",i,i*i); }
The new paradigm (woof) is that a variable should have the smallest scope possible to ease reading and interpretation of code (by humans).

Next: Exit strategy: Single exit point can be easily bad.

2010-04-20

How to create a fast thread-safe singleton initialization in C++

1st: We need a lock. On windows it can use critical sections. Keywords: critical section, lock
class Lock {
    CRITICAL_SECTION mSection;
public:
    Lock(){ InitializeCriticalSection(&mSection); }
    ~Lock(){ DeleteCriticalSection(&mSection); }
    void Acquire(){ EnterCriticalSection(&mSection); }
    void Release(){ LeaveCriticalSection(&mSection); }
};
2nd: We need a guard for the lock. Just for convenience and to be foolproof. Keyword: RAII, guard. See also: auto_ptr.
class Guard {
    Lock *pLock;
public:
    Guard(Lock &lock)
    : pLock(&lock)
    { pLock->Acquire(); }
    ~Guard(){ pLock->Release(); }
};
3rd: We can get down to business with our singleton. Do not forget to hide the default constructors and the '=' operator. Keywords: singleton, multi-thread, thread-safe, storage, operator overloading.

singleton.h:
class Singleton {
public:
    static Singleton *GetInstance();
    // other public members
private:
    Singleton();
    ~Singleton();
    Singleton(const Singleton&);
    const Singleton& operator=(const Singleton&);

    static Singleton* pInstance;
    static Lock instanceLock;
    // other private members
};
singleton.cpp:
#include "singleton.h"

// Storage place for static members:
Singleton* Singleton::pInstance = 0;
Lock Singleton::instanceLock;

Singleton::Singleton(){ /* as you wish */ }
Singleton::~Singleton(){ /* as you wish */ }

Singleton* Singleton::GetInstance()
{
    if(pInstance)
        return pInstane;
    Guard g(instanceLock);
    if(!pInstance)
        pInstance = new Singleton();
    return pInstance;
}

Feel free to search the web for the keywords, or any word you read here.