Tuesday, September 1, 2015

Building your own unit-testing framework

When you want to apply a test-driven design approach, you will probably find that almost none of the unit-test frameworks really fits your needs. So, if your company does not already use a testing framework, it is worth developing your own framework!

Below is a step-by-step development of a unit-testing framework. It is basically a summary of Kevlin Henney's "Raw TDD" workshop I attended during ACCU 2015. The workshop was so revealing, that I had to record it here.

Monday, December 8, 2014

C++ Bloopers - references to temporary objects

Breaking encapsulation of classes to expose internal state, is always a source for potential errors.

STL had to do this to allow communication with C's lower level strings and arrays. And here's how you can mess things up when using std::string.

Wednesday, May 14, 2014

Building custom iterators

Once one realizes that STL algorithms open the doors for expression, readability, maintenance and reusability, he wants to have it for the classes he creates.

Of course, you shouldn't expose the internals of your class, so you need a way to offer exploration of your object's data, without exposing implementation details, like the underlying data structures:

The quick-and-dirty way is to  provide algorithms for your class.

class Polygon {
        vector<Point> vertices;
    public:
        template <class Func>
        Func for_each_vertex ( Func f );  // access by vertex

        template <class Func>
        Func for_each_edge ( Func f );  // access by edge
};


However, this gives you limited expression. You soon have to write versions for find(), find_if(), copy(), copy_if(), transform(), count_if(), all_of(), any_of(), none_of(), and you end up replicating part of STL algorithms for each class, for each access type (by vertex, by edge).

Read this article, to see how you can implement this interface:

class Polygon {
        vector<Point> vertices;
    public:
        vertex_iterator begin_vertex();
        vertex_iterator end_vertex();

        edge_iterator begin_edge();
        edge_iterator end_edge();
};

Monday, May 5, 2014

inline, static, extern functions and namespaces

How safe do you think it is to write this piece of code in your .cpp file ?


file.cpp
struct Point {
    double *px;
    double *py;

    Point (double x, double y) {
        px = new double(x);
        py = new double(y);
    }
    ~Point() {
        delete x;
        delete y;
    }

    // other members ...
};

Read more why this is the most dangerous piece of code you can write in your .cpp, and it is more likely to be spotted after releasing the project...

Tuesday, March 18, 2014

The law of least surprise

Extreme programming argues that documentation is not needed, since code is the best description of what the program does. In order for this to be true, code has to be readable. Very readable.

It is important to be able to tell what is the direction of data in every line you read. In the following case, which variable is the source and which is the destination ?

    Array *names;
    struct Detail details;
    ...
    set_name_details (names, &details);

Here is a simple rule to make the caller code clearer...

Tuesday, March 11, 2014

The Roll - Unroll Pattern

The pattern that is most predominant in programming is:
  • Setup some state
  • Do some work
  • Clean up
Manual housekeeping of this repetitive task requires too much care and energy, from the programmer’s side. Repetitive tasks sounds like a work that should be automated, rather than maintained manually.
Read how you can create an elegant piece of code, while reducing the maintenance load.

Saturday, March 8, 2014

Algorithms should read like pseudocode

Algorithms should read like pseudocode
When an algorithm is described like pseudo-code, there is hardly ever any mention about the underlying data-structures. No statement is made on whether a list, a dynamic array, or a binary tree should be used.
With C++, it is possible to code in such a way.

Saturday, November 23, 2013

STL set operations

There are some useful algorithms that run on two sets of values
  • set_union
  • set_intersection
  • set_difference
  • set_symmetric_difference
These operations are very useful, but their names are a bit confusing.
Here's a graphical interpretation of how they work, and it is how I remember them:

Exploring ways to express an algorithm

Suppose you want to rewrite the following loop
  
struct Shape {
    int rgb_color() const;
};

map<int, Shape*> id_to_shape;
vector<int> bright_colors;


for( map<int, Shape*>::iterator it=id_to_shape.begin(); it != id_to_shape.end(); ++it )
{
    int color = it->second->rgb_color();
    if (color_is_bright (color))
        v.push_back(bright_colors);
}
  
Here follows a tour in ways that this loop could be expressed.

Tuesday, November 12, 2013

Moving from legacy data structures to STL containers

When one is introduced to the STL containers there is a temptation to switch from the non-homogeneous legacy C-based data structures to the more smooth and standard containers. The existing code cannot magically turn all Trees to std::maps, DynamicArrays to std::vectors, LinkedLists to std::lists, so old code will probably still use old data structures.

So, a question arises:

  • I have C and C++ functions that take Tree*, DynamicArray*, etc as arguments. Isn't it going to be awkward to introduce functions that now take vector, map, deque as well ?
  • Do I have to make a version of the function for each data type ?

Friday, November 8, 2013

How to design API headers

Library headers (API) should be minimal and not change very often. If this directive is followed, then the API is more direct, and any internal changes do not reflect to recompiling the whole user project.

The following article describes what steps to take to achieve this goal on an C++ API header.

Thursday, November 7, 2013

How does std::unordered_set compare to std::set ?

What are the differences between std::set and std::unordered_set ?

Here is a graphical and quantitative explanation of 
  • how unordered_set works, 
  • how fast it can access data, 
  • how much memory it occypies, and 
  • how it compares to std::set.


Wednesday, November 6, 2013

Forward declarations vs includes in headers

What should be included and what can be forward declared in this header ?
class Polygon : public Shape {

public:
    void setBasicCurve (const Bezier& curve);
    void magnify (Vector direction);
    void setPoints (const vector<Point*>& points);

private:
    Plane*             m_surface;
    std::list<Point*>  m_points;
    Color              m_color;
    Bezier&            m_basic_curve;

    static Type        m_shape_type;

};

Here are some practical tips to keep your header files lean.

Monday, November 4, 2013

Using a std::unordered_set

It's easy to use an unordered_set, or unordered_map with a basic key type, like int, float, string.
You simply set it up like

     std::unordered_set<string> simple_hash_table;  

But how does one create hash functors and compare functors for a more complex key?

How to pass ownership of C objects to STL containers


Mixing C code with C++ code

I have a number of C entities (say Nodes), which I want to store to a std::vector temporarily.
The C interface I have to manipulate these nodes consists of:
  • Node *newNode();             constructs such nodes
  • void  freeNode(Node *);      frees such nodes
Can I use the RAII technique, so that they are properly freed when the vector goes out of scope?

Sunday, November 3, 2013

How is std::deque implemented ?

Deque is sometimes thought of as an dynamic array that is comprised of linked arrays.

typical deque layout

Such a structure could lead to extremely fast insert and remove operations.

Exactly what performance should one expect from a std::deque implementation though?


Saturday, November 2, 2013

Generic C-Trees and C++ std::maps

How many lines of code do I need, to set up a typical tree structure? What are the pros and cons between a C-style generic tree and an std::map or an std::set ?

Wednesday, October 30, 2013

How to write a compare function


std::map , std::set and std::sort may require that you write a custom compare function, so the elements can be sorted.
Writing the compare function correctly is critical, as a mistake can make your program crash.
There is a typical pattern you can follow, to write a compare function.