2

I'm implementing a custom templated container as part of a learning project in C++. The container makes use of different components like serialization, memory management, iterators. I am wondering what is the best way to organise the code.

Option 1: Put everything into one header file:

I've seen this in several example online. But by doing this I'm going to end up with a file of several thousand lines long:

// container.hpp
template <typename params>
class Container {

public:
    // params is a struct with typedefs and static variables 
    // used to configure the container at compile time

    // I define additional typedefs and static variables here from params::

public:
    class iterator {

        // can use the typedefs and variables above
    };

    class memory {

        // can use the typedefs and variables above
    };
};

Option 2: Split the code into multiple headers

Each file contains the implementation of 1 component.

// memory.hpp
template <typename Container>
class memory {

public:
    // typedefs and static variables from Container::

};

// iterator.hpp
template <typename Container>
class iterator {

public:
    // typedefs and static variables from Container::

};

// container.hpp
#include "iterator.hpp"
#include "memory.hpp"

template <typename params>
class Container {
public: 
    // typedefs and static variables here from params::


    typedef Container<params> self_type;


    iterator<self_type> begin();

private:
    memory<self_type> mem;
};

What are the arguments to chose?

Solution 1 seems cleaner; something bugs me about having to pass the container type to the memory and iterators in solution 2. But at the same time the code is organised in different files in solution 2. Each file contains the implementation of 1 component.

Is it just a matter of personal preference? Or are there objective reasons to choose one solution over the other? Or is there a completely different and better approach?

  • 1
    Having a file which is several thousand lines long should instantly be a red flag which screams "Don't do this!" -- put yourself in the position of someone else coming along to some code they're seeing for the first time and immediately being faced with such a huge header file - would you want to see that or see a solution which is broken down into lots of smaller, sensibly named and sensibly structured files instead? – Ben Cottrell Feb 15 at 10:49
0

Is it just a matter of personal preference or is there a reason why to choose one solution over the other ? (or a completely different approach).

No, that's not a matter of personal preference.

It's always better to have the several components being implemented in separate header files (as you suggest for your 2nd solution).

This will increase

  • readability
  • maintanability
  • reusability
|improve this answer|||||
  • If the splitting necessitates making code more complicated (as option 2 does), neither readability nor maintainability is improved. If the different headers still have tight dependencies on each other, reusability is not improved. – Sebastian Redl Feb 15 at 11:09
2

In short

Option 2 is better and there are objective reason for this. And yes, the approach can be improved.

More details: why option 2 is to be preferred

Option 1 lacks separation of concerns. What does this mean?

  • Imagine that one day your project could afford to hire a team, with an expert of serialization, another specialist for iteration, and a guru of memory management.
  • Option 1 would make it difficult for this hypothetical team to work together. They'd all work on the same file. And even with a good repository management, there would be merge conflicts and lots of disputes about who is in charge of what.

Option 2, defines clear boundaries between the components of your solution. This has lots of benefits:

  • smaller file that are easier to read: You can for example grasp what is in container.hpp without necessarily having to read iterator.hpp;
  • easier changes;
  • encourages potentially reusable sub-components.

More details: how to do better ?

You should include all your components in your own namespace. This is important, because in option 1 iterator is not exposed under its own name but as Container::iterator whereas in option 2, without namespace, it would be known as iterator which could create some ambiguities.

Another possible improvement, could be to separate the definition of each template class from its implementation in two files:

  • This multiplies of course the files. One could think it's of no use because the full code of the C++ templates must be included in the compilation units in which they are used.
  • But it brings the additional benefit of separating the interface from the implementation, at least in the source code.

Finally, you may find some more inspiration in the boost guidelines for headers.

|improve this answer|||||

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.