MemCache++ is a lightweight, type-safe, easy-to-use and full-featured Memcache client. It was developed by Dean Michael Berris, a C++ fanatic who currently works at Google Australia. He is also part of the Google delegation to the ISO C++ Committee.
Studying well-designed libraries is a great way to improve your C++ design and implementation skills. The goal of this article is to explore some of the design choices that make memcache++ easy to understand and use.
Namespace Modularity
Namespaces are a good way to modularize an application. Unfortunately, this feature is underused in C++ projects—a quick look at random open-source C++ projects makes this clear. Moreover, when we search for the definition of a C++ namespace, the common one looks like this:
A namespace defines a new scope. They provide a way to avoid name collisions.
Often, collision avoidance is presented as the primary motivation rather than modularity—unlike in C# and Java, where namespaces are more commonly used to structure applications. However, some modern C++ libraries like Boost use namespaces to structure the library well and encourage developers to use them.
What about namespace modularity in memcache++?
Here's the dependency graph between memcache++ namespaces:

Namespaces are used for two main reasons:
- Modularize the library.
- Hide details, like the "memcache::detail" namespace; this approach is very interesting if we want to inform the library user that they don’t need to directly use the types inside this namespace. In C# the "internal" keyword does the job, but in C++ there’s no way to hide public types from the library user.
memcache++ makes effective use of namespaces. However, a dependency cycle exists between memcache and memcache::detail. We can remove this dependency cycle by searching for types used by memcache::detail from memcache.
For that, we can execute the following CQLinq query:
from t in Types where t.IsUsedBy("memcache.detail")
&& t.ParentNamespace.Name=="memcache"
select new { t,t.TypesUsingMe }Here’s the result after executing the query:

To remove the dependency cycle, we can move pool_directive and server_pool_test to the memcache namespace.
Which paradigm is used most in modern C++ code: generic programming or OOP?
In the C++ world, two schools of thought are very popular: object-oriented programming and generic programming; each approach has its advocates. This article explains the tension between them.
Which paradigm is most used by memcache++?
To answer this question, let’s first search for generic types:
from t in Types where t.IsGeneric && !t.IsThirdParty select t

What about the non-generic ones?
from t in Types where !t.IsGeneric && !t.IsGlobal && !t.IsNested
&& !t.IsEnumeration && t.ParentProject.Name=="memcache"
select t

Almost all the non-generic types are exception classes, and to get a better idea of their proportion, the treemap view is very useful.

The blue rectangles represent the result of the CQLinq query, and as we can see, only a minimal part of the library is related to non-generic types.
Finally, we can search for generic methods:
from m in Methods where m.IsGeneric && !m.IsThirdParty select m

As we can see, memcache++ mostly uses generics, but that’s not enough to confirm that it follows the generic programming approach in C++. To check that, a good indicator is the use of inheritance and dynamic polymorphism, which OOP uses heavily. However, in the generic approach, inheritance is very limited and dynamic polymorphism is avoided.
Let’s search for types that have base classes.
from t in Types where t.BaseClasses.Count()>0 && !t.IsThirdParty
&& t.ParentProject.Name=="memcache"
select t

It’s normal that the exception classes use inheritance, but what about the other classes? Do they use inheritance for dynamic polymorphism purposes? To answer this question, let’s search for all the virtual methods.
from m in Methods where m.IsVirtual select m

Only the exception class has a virtual method.
If dynamic polymorphism is not used, what approach can we adopt when we need different behavior for specific classes?
The common solution in the modern C++ approach is to use policies. Here’s a short definition from Wikipedia:
"The central idiom in policy-based design is a class template(called the host class),taking several type parameters as input, which are instantiated with types selected by the user (called policy classes), each implementing a particular implicit interface (called a policy)."memcache++ has many policies inside the memcache.policies namespace.

Let’s look at an example from memcache++ to better understand policy-based design.
memcache++ uses the basic_handle type to implement all commands like add, set, get and delete from the cache. This class is defined like this:
template <
class threading_policy = policies::default_threading,
class data_interchange_policy = policies::binary_interchange,
class hash_policy = policies::default_hash
>
struct basic_handle
memcache++ is thread-safe, and in a multithreaded context it has to manage synchronization; by default the threading_policy is "default_threading", where no special processing is required. However, for multithreading, the policy used is "boost_threading".
Let’s take a look at the connect method implementation.
void connect(boost::uint64_t timeout = MEMCACHE_TIMEOUT) {
typename threading_policy::lock scoped_lock(*this);
for_each(servers.begin(), servers.end(), connect_impl(service_, timeout));
};
If threading_policy is "default_threading", the first line has no effect because the lock constructor does nothing. However, if it’s the boost_threading one, the lock uses Boost to synchronize between threads.
Using policies gives us greater flexibility to implement different behaviors, while remaining relatively easy to understand and use.
Generic Functors
memcache++ implements many commands to interact with the cache, such as add, get, set, and delete. The command pattern is a good candidate for such a case. memcache++ implements this pattern using generic functors; here’s a CQLinq query to get all functors:
from t in Types where t.Methods.Where(a=>a.IsOperator
&& a.Name.Contains("()")).Count()>0
select t

A functor encapsulates a function call with its state, and it can be used to defer the call to a later time and act as a callback. Generic functors give more flexibility than normal functors.
Public Interface exposed
How a library exposes its capabilities is very important because it affects both flexibility and ease of use. To discover that, let’s search for the communication between the test project and the memcache++ library.
from m in Methods where m.IsUsedBy ("test")
select m

The test project mainly uses generic methods to invoke memcache++ functionalities. What are the benefits of using template methods? Why not use classes or functions?
With the OOP approach, the library interface is composed of classes and functions, and for well-designed ones, abstract classes are used as contracts to enforce low coupling. This solution is very interesting but has some drawbacks:
- The interface becomes more complicated and may change frequently. To illustrate this, let’s take the add method exposed by memcache++. If we don’t use the generic approach, many methods must be added, one for each specific type: int, double, string…
The generic add method is declared as add<T>, where T is the type; in this case, we need only one method, and even if we want to add another type, no change is required in the interface.
- The interface is less flexible. For example, if we expose a method like this:
calculate(IAlgo* algo).
The user must provide a class inheriting from IAlgo. However, if we use generics and define it as calculate<T>, the user only has to provide a class with the needed methods and doesn’t necessarily have to inherit from IAlgo. And if IAlgo changes to IAlgo2 because new methods are added, the library user will not be affected.
Ideally, the interface exposed by a library must not have any breaking changes, and the user must not be impacted when changes are introduced in the library. The generic approach is the most suitable for such constraints because it’s very tolerant when changes are needed.
External API used
Here are the external types used by memcache++:

memcache++ mostly uses Boost and the STL to achieve its goals; here are some Boost features used:
- multithreading.
- algorithm.
- spirit.
- asio.
- unit testing.
From the STL, containers are used most often.
So finally, what are the advantages of using the generic approach?
- The first indicator of the efficiency of memcache++’s design choices is the number of lines of code (LOC), which is only around 600 lines; this result is due to two main reasons:
- Using the generic approach removes boilerplate code.
- Leveraging the richness of Boost and the STL.
- The second strength is its flexibility: any change impacts only a minimal portion of code.
