C++ simple and resilient data

So little C++ so much good!

Simple things are simply the most useful things. But one has to be careful not to make them simpler than that.

A co-worker / C++ student, came to me the other day, puzzled. Her code with cruft removed:

How did she get into this mess?

Simple. That is a type that has methods and data all static.  That means all is shared on the level of the type. Not instances. There is even no point in making an instance of that class

There are valid situations approving of that design. Without questioning it we went down the path to the solution at the other end of the garden.

Not patient? Not a problem. Github repo is here. For the code regarding this post please look into dbj_nifty_store.h

Aiming for the happy end

In this part of the scenario, the key actor is very simple and very resilient C++. We will develop:

A single template whose definition creates all static types, holding a single piece of data, uniquely identifiable and thread resilient.

This is the core of the modern set of wrappers around your legacy data. And the usage is deceptively simple.

Simple, small resilient, and fast. That is the ideal type to extend it and add for example “atomicity” or knowledge of persistent storage without changing the original type.

Same type many stores

What are those guid_a and guid_b template arguments? They are identity providers. Simple functions returning dbj::GUID.

Remember one data<> type stores only one single piece of data. And that template definition is a class with only statics inside.

To keep the store simple and to differentiate between stores we add the second template argument as the unique identifier of the type to be defined when the template gets arguments. Consider this.

Now using the above I want to have two storages of bool data. How do I do that?

The only way out is to add some kind of identification without abandoning the static data concept.

The unique identity of the type defined is the role of the second argument in the data<> template. And since up to C++20 concrete type as a template argument can not be a class we are using function pointers.

Synopsis. Hint: see the code online.

store_a and store_b are two distinct types.

The dbj::data<> template when defined is a type that has only one static data member and no methods, ctors or dtors.

Instance less programing

Recap. The template definition is a type. And there is no point in making instances of the dbj::data<T> type. Everything is static inside.

Thus there is no possibility (and no need) for passing instances as e.g. function arguments. It is enough to pass the type only

Above is all zero overhead.

In the code ( file dbj_nifty_store.h) there is one simple usage example.

The resilient identification

dbj::GUID the suite will be detailed in the next post.  The testing function is on the bottom of the same header.  I will just mention the unique identification available.

That is not a mockup. That is real UIID aka GUID. The value of that solution will be much more obvious with complex types handled in your complex scenarios. Hint: for example transaction processing.

You will easily add more functionality by adding functions around it, without touching the core template itself.

Github repo is here. It contains also the code from the next post on this GUID used here.