Articles & Books

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()).

Quick Q: Why doesn't c++ have a specified order for evaluating function arguments?

Quick A: In order to get the best performance.

recently on SO:

Why doesn't c++ have a specified order for evaluating function arguments?

C++ leaves as much as practical up to the implementation of the compiler, especially where optimization opportunities might occur. Before fixing something like this, existing compiler writers are consulted to see if there is a cost.

Some order of evaluation guarantees surrounding overloaded operators and complete-argument rules where added in C++17. But it remains that which argument goes first is left unspecified. In C++17, it is now specified that the expression giving what to call (the code on the left of the ( of the function call) goes before the arguments, and whichever argument is evaluated first is evaluated fully before the next one is started, and in the case of an object method the value of the object is evaluated before the arguments to the method are. (There may be some minor errors in this description: ask a narrow question about it for a more vetted answer).

These where vetted and determined to not cause significant prolems for existing compilers. Reordering of arguments was considered, and discarded, presumably for good reasons. Or even poor reasons, like existing compilers have a default order and it could break (possibly non-compliant) code on that compiler to force them all to do it in one global order.

In short, C++ leaves lots of freedom to compiler writers. This has let compiler writers find optimization opportunities in strange crannies. The kind of optimizations available today are way beyond what the original writers of C++, let alone C++, may have suspected where practical or be considered reasonable.

Quick Q:Why does std::set seem to force the use of a const_iterator?

Quick A: A set does not allow the modification of its keys.

Recently on SO:

Why does std::set seem to force the use of a const_iterator?

A set is like a map with no values, only keys. Since those keys are used for a tree that accelerates operations on the set, they cannot change. Thus all elements must be const to keep the constraints of the underlying tree from being broken.

Memory consistency made simple(ish)--Glennan Carnie

How to synchronize between threqds or

Memory consistency made simple(ish)

by Glennan Carnie

From the article:

The C++11 memory consistency model is probably one of the most significant aspects of Modern C++; and yet probably one of the least well-understood.  I think the reason is simple:  it’s really difficult to understand what the problem actually is.

The memory consistency problem is a concurrency problem.  That is, it’s a problem that occurs when we start writing multi-threaded code.  More specifically, it’s a parallelism problem – the real subtleties occur when you have two or more processors executing code...

 

Const Correctness--Arne Mertz

Do you use const well?

Const Correctness

by Arne Mertz

From the article:

Writing const correct code is about more than using const in a few places and letting the compiler figure out if it makes sense.

There are two components about using the keyword const in C++ code: A syntactic component and a semantic component...

Quick Q: Conditional use of std::lock_guard

Quick A: Use std::unique_lock instead.

Recently on SO:

Conditional use of std::lock_guard

How about this one?

void bar(std::mutex * optionalMutex = nullptr)
{
        auto lockScope = (optionalMutex == nullptr) ?
                           std::unique_lock<std::mutex>()
                         : std::unique_lock<std::mutex>(*optionalMutex);

}

Explanation: You're compiler had trouble with your prior statement because, you can not suddenly change the type of the ternary ? expression, i.e. the literal 0 is not a std::lock_guard and vice versa. So I changed the two branches to the same type, here std::unique_lock<std::mutex> because lock_guard isn't designed be used without a valid mutex. But still prefer std::lock_guard over std::unique_lock in the simpler cases, because it will make you code more readable.

Also your statement wasn't viable for the compiler, i.e. even syntactical correct, because the variable lockScope would only have existed in one branch.

Move safety - know what can be done in the moved-from state--Jonathan Müller

What state is an object after move?

Move safety - know what can be done in the moved-from state

by Jonathan Müller

From the article:

C++ programmers have this notion of exception safety. It is a very useful concept. With it one can easily describe the post-conditions of a function if it throws.

There is another situation where you need to easily describe some post-conditions: when talking about the state of an object after a move operation, i.e. after a move constructor or move assignment operator. I thus want to introduce vocabulary for those post-conditions of the right-hand argument similar to the exception safety of a function: The move safety, if you will.

The exception safety describes the post-conditions of a function if the function throws an exception. Similarly, the move safety describes the post-conditions of the object after a move operation. It thus gives information about what can be done safely with a moved-from object...