C++ Core Guidelines: Interfaces II

Interfaces are a contract between a service provider and a service consumer. The C++ Core Guidelines has 20 rules to make them right because "interfaces is probably the most important single aspect of code organization".

Lego dimensions.svg

I wrote in my last post about the first 10 rules. Today I will finish my job and write about the remaining 10 rules.

Let's directly dive into the details.

I.11: Never transfer ownership by a raw pointer (T*)

There is a conceptional issue with this code.

X* compute(args)    // don't
    X* res = new X{};
    // ...
    return res;


Who deletes the pointer X? There are at least three alternatives to deal with the ownership problem:

I.12: Declare a pointer that must not be null as not_null

What is the semantic difference between the three variations of the following function length?

int length(const char* p);            // it is not clear whether length(nullptr) is valid

int length(not_null<const char*> p);  // better: we can assume that p cannot be nullptr

int length(const char* p);            // we must assume that p can be nullptr


The intention of variations two and three of length is quite obvious. The second variation accepts only a non-null pointer, the third version accepts a nullptr. You may have already guessed it. not_null if from the GSL.

I.13: Do not pass an array as a single pointer

Passing arrays as a single pointer is quite an error prone.

void copy_n(const T* p, T* q, int n); // copy from [p:p+n) to [q:q+n)


What will happen if n is too big? Right: undefined behaviour. The GSL offers a solution, called spans.

void copy(span<const T> r, span<T> r2); // copy r to r2


Spans deduce their number of arguments.

I.22: Avoid complex initialization of global objects

Global objects provide a lot of fun. For example, if they are in different translation units, their order of initialisation is not defined. The following code snippet has undefined behaviour.

// file1.c

extern const X x;

const Y y = f(x);   // read x; write y

// file2.c

extern const Y y;

const X x = g(y);   // read y; write x

I.23: Keep the number of function arguments low

There is a simple rule: one function should do exactly one job. If that is the case the number of function arguments automatically become low and, therefore, the function is easy to use.

To be honest, the New Parallel Algorithms of Standard Template Library such as std::transform_reduce often break this rule.

I.24: Avoid adjacent unrelated parameters of the same type

What are the source and the destination of the following copy_n function? Any educated guess?

void copy_n(T* p, T* q, int n); 


I often have to look for documentation.

I.25: Prefer abstract classes as interfaces to class hierarchies

Of course, that is an obvious and long-established rule for object-oriented design. The guidelines provide two reasons for this rule.

  • abstract classes are more likely to be stable than base classes
  • bases classes with state and non-abstract methods put more constraints on derived classes

I.26: If you want a cross-compiler ABI, use a C-style subset

ABI stands für Application Binary Interface.

This is a strange rule in C++ guidelines. The reason is that "Different compilers implement different binary layouts for classes, exception handling, function names, and other implementation details.". On some platforms, there are common ABIs emerging. If you use a single compiler, you can stick to the full C++ interface. In this case, you have to recompile the code.

I.27: For stable library ABI, consider the Pimpl idiom

Pimpl stands for a pointer to implementation and is the C++ variation of the bridge pattern. The idea is that a non-polymorphic interface holds the pointer to its implementation, therefore, modification of the implementation doesn't require recompilation of the interface.

Here is the example from the C++ Core Guidelines:

interface (widget.h)
class widget {
    class impl;
    std::unique_ptr<impl> pimpl;
    void draw(); // public API that will be forwarded to the implementation
    widget(int); // defined in the implementation file
    ~widget();   // defined in the implementation file, where impl is a complete type
    widget(widget&&) = default;
    widget(const widget&) = delete;
    widget& operator=(widget&&); // defined in the implementation file
    widget& operator=(const widget&) = delete;

implementation (widget.cpp)

class widget::impl {
    int n; // private data
    void draw(const widget& w) { /* ... */ }
    impl(int n) : n(n) {}
void widget::draw() { pimpl->draw(*this); }
widget::widget(int n) : pimpl{std::make_unique<impl>(n)} {}
widget::~widget() = default;
widget& widget::operator=(widget&&) = default;


The pimpl is the pointer that holds the handle to the implementation.

For an in-depth discussion of this C++ idiom, read the GOTW #100 article by Herb Sutter. GotW stands für Guro of the Week.

I.30: Encapsulate rule violations

Sometimes code is ugly, unsafe, or error-prone because of various reasons. Put the code in one place and encapsulate it with an easy to use interface. That is called abstraction which you have sometimes to do. To be honest, I have no problem with that code, if the internal code used is stable and the interface lets you only use it in the correct way.

What's next?

In the last posts including the current one I often mentioned the guideline support library. Now it's time to have a look at insight and I will write about it in the next post.



Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, Marko, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Animus24, Jozo Leko, John Breland, espkk, Louis St-Amour, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Neil Wang, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Tobi Heideman, Daniel Hufschläger, Red Trip, Alexander Schwarz, Tornike Porchxidze, Alessandro Pezzato, Evangelos Denaxas, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Dimitrov Tsvetomir, Leo Goodstadt, Eduardo Velasquez, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, and Michael Young.


Thanks in particular to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, and Rusty Fleming.



My special thanks to Embarcadero CBUIDER STUDIO FINAL ICONS 1024 Small



I'm happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

Bookable (Online)


Standard Seminars (English/German)

Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.


Contact Me

Modernes C++,


My Newest E-Books

Course: Modern C++ Concurrency in Practice

Course: C++ Standard Library including C++14 & C++17

Course: Embedded Programming with Modern C++

Course: Generic Programming (Templates)

Course: C++ Fundamentals for Professionals

Interactive Course: The All-in-One Guide to C++20

Subscribe to the newsletter (+ pdf bundle)

Blog archive

Source Code


Today 4837

Yesterday 8162

Week 21707

Month 139909

All 7407749

Currently are 159 guests and no members online

Kubik-Rubik Joomla! Extensions

Latest comments