Articles & Books

[C++17] Structured Bindings - Convert struct to a tuple (simple reflection)

An interesting piece of code!

[C++17] Structured Bindings - Convert struct to a tuple (simple reflection)

From the article:

Very simple approach to convert any struct (up to N members) to a tuple using C++17 structured bindings and the idea from Boost.DI (http://boost-experimental.github.io/di/cppnow-2016/#/7/11) used to detect type constructor traits.

How Bloomberg is Advancing C++ at Scale--John Lakos

Interesting interview:

How Bloomberg is Advancing C++ at Scale

by John Lakos

From the article:

John Lakos manages the Bloomberg Development Environment group, which offers a set of C++ software libraries, development tools, and methodology to well over a thousand Bloomberg developers. He is an authority on large-scale C++ software infrastructure, receiving recent acclaim for two publications by Pearson Education on methodology for industrial software development [Part 1, Part 2]. BDE and its libraries are open source and can be found on GitHub. In this conversation, Lakos discusses the importance of instilling process and discipline in all software development projects...

Quick Q: Efficiency of postincrement v.s. preincrement in C++

Quick A: The difference is only marginal with optimizations enabled.

Recently on SO:

Efficiency of postincrement v.s. preincrement in C++

It is true - although perhaps overly strict. Pre increment doesn't necessarily introduce a data dependency - but it can.

A trivial example for exposition:

a = b++ * 2;

Here, the increment can be executed in parallel with the multiplication. The operands of both the increment and the multiplication are immediately available and do not depend on the result of either operation.

Another example:

a = ++b * 2;

Here, the multiplication must be executed after the increment, because one of the operands of the multiplication depends on the result of the increment.

Of course, these statements do slightly different things, so the compiler might not always be able to transform the program from one form to the other while keeping the semantics the same - which is why using the post increment might make a slight difference in performance.

A practical example, using a loop:

for(int i= 0; arr[i++];)
    count++;

for(int i=-1; arr[++i];)
    count++;

One might think that the latter is necessarily faster if they reason that "post-increment makes a copy" - which would have been very true in the case of non-fundamental types. However, due to the data dependency (and because int is a fundamental type with no overload function for increment operators), the former can theoretically be more efficient. Whether it is depends on the cpu architecture, and the ability of the optimizer.

For what it's worth - in a trivial program, on x86 arch, using g++ compiler with optimization enabled, the above loops had identical assembly output, so they are perfectly equivalent in that case.

 

Rules of thumb:

If the counter is a fundamental type and the result of increment is not used, then it makes no difference whether you use post/pre increment.

If the counter is not a fundamental type and the result of the increment is not used and optimizations are disabled, then pre increment may be more efficient. With optimizations enabled, there is no difference.

If the counter is a fundamental type and the result of increment is used, then post increment can theoretically be marginally more efficient - in some cpu architecture - in some context - using some compiler.

If the counter is a complex type and the result of the increment is used, then pre increment is typically faster than post increment. Also see R Sahu's answer regarding this case.

Take benefit from simple laziness -- Krzysztof Ostrowski

Presentation of simple techniques that can be used to delay execution of costly computations.

Take benefit from simple laziness

by Krzysztof Ostrowski

From the article:

In the C++ world lazy evaluation is usually linked to templates and their property that separates definition from actual instantiation. Given that we can, for instance, delay binding of a symbol.

Besides the above, we have old plain short circuiting inherited from C language: logical operators like && (and), || (or) and ternary operator ?:. They can be used as constructions to lazy execute (expressions must be valid C++) some of the expressions. With short circuiting we want to delay or skip execution of costly operations.

Turning Egyptian Division Into Logarithms -- David Sanders

Insights I've had while reading Elements of Programming and From Mathematics to Generic Programming

Turning Egyptian Division into Logarithms

by David Sanders

From the article:

I have benefitted greatly from multiple readings of Elements of Programming by Alexander Stepanov and Paul McJones as well as From Mathematics to Generic Programming by Stepanov and Daniel Rose. Each time I read either work, I learn something new.

In this article, I describe an extension to the ancient Egyptian division algorithm to yield logarithm and remainder in addition to quotient and remainder.

Quick Q: 'Constexpr' vs 'extern const'. Which has priority?

Quick A: If you need a compile time constant, you cannot use extern.

Recently on SO:

'Constexpr' vs 'extern const'. Which has priority?

Using extern const in the header file only tells the compiler that the variable exists and that it is not modifiable. It doesn't tell the compiler its value which means it's not a compile-time constant anymore. If it's not a compile-time constant then it can't be used for e.g. case or as an array size.

As said by M.M in the comment, either use

const int MAX_NUMBER_OF_ROWS= 99;

or

constexpr int MAX_NUMBER_OF_ROWS= 99;

directly in the header file and it will be a compile-time constant in all translation units that include the header file.

Overload 134 is now available

ACCU’s Overload journal of August 2016 is out. It contains the following C++ related articles.

Overload 134

From the journal:

Some Big-Os are Bigger Than Others
Big-O notation is often used to compare algorithms. Sergey Ignatchenko reminds us that asymptotic limits might not be generally applicable. by Sergey Ignatchenko

Kill the Clones
Problems in code can hide in surprising places. Adam Tornhill demonstrates how to detect software clones and uncover hidden dependencies. by Adam Tornhill

Implementing SNAAAKE
Almost everyone knows the game Snake! Thaddaeus Frogley shares a diary of how his implementation grew over time. by Thaddaeus Frogley

C++ Antipatterns
Certain mistakes crop up frequently in C++. Jonathan Wakely offers some pro-tips to help you avoid common errors. by Jonathan Wakely

Testing Propositions
Is testing propositions more important than having examples as exemplars? Russel Winder considers this hypothesis. by Russel Winder

Quick Q: unordered_map element being deleted

Quick A: Once a value is deleted, iterators pointing to it become invalid.

Recently on SO:

unordered_map element being deleted

After you call my_umap.erase(...), your iterator becomes invalid:

cppreference.com says:

References and iterators to the erased elements are invalidated. Other iterators and references are not invalidated.
This means that once the item is erased, the iterators that pointed to it are no longer valid.

You've got a couple of options:

1. Use the iterator to erase, and use the return value of erase()

Since C++11, erasing by iterator will return an iterator pointing to the next item in the map. So you can use this to keep your iterator valid:

auto it = my_umap.begin();

while (it != my_umap.end()) {

    MyStruct& myStruct = it->second;
    const bool deleteEntry = myStruct.ts.IsElapsed(std::chrono::seconds(5));

    if(deleteEntry){
        assert(my_umap.size() >= 1);
        it = my_umap.erase(it);  // <-- Return value should be a valid iterator.
    }
    else{
        ++it;  // Have to manually increment.
    }
}

2. Store your iterators in a list object and erase after iteration.

Alternatively, you can store delete candidates in a list object (e.g. vector and delete them after your initial iteration:

std::vector<MapType::iterator> deleteCandidates;

for(auto it = my_umap.begin(); it != my_umap.end(); ++it){

    MyStruct& myStruct = it->second;
    const bool deleteEntry = myStruct.ts.IsElapsed(std::chrono::seconds(5));

    if(deleteEntry)
        deleteCandidates.push_back(it);
}

for (auto it : deleteCandidates) {
    my_umap.erase(it);
}

As for why your assertion is failing, you're probably encountering undefined behaviour by accessing an invalid iterator, making your for loop believe that the map is still not empty (because invalidIterator != my_umap.end()).