Articles & Books

Quick Q: std::rethrow_exception and thrown exception type

Quick A: std::make_exception_ptr creates a reference on a copy.

Recently on SO:

std::rethrow_exception and thrown exception type

From documentation for std::make_exception_ptr:

Creates an std::exception_ptr that holds a reference to a copy of e.

Unfortunately, copying e means you get object slicing (which @Mohamad Elghawi points out is also more prominently mentioned later on that page). When you call std::make_exception_ptr<RecognitionException>, it will hold a copy of a RecognitionException, not any derived class.

But you don't need exception_ptr at all here. Even though reportError does not have the try...catch in scope, you can still use throw; to re-throw the current exception.

#include <stdio.h>

struct A { virtual ~A() = default; };
struct B : A { };

void reportError() {
  try {
    throw;
  }
  catch (B &) {
    puts("caught B");
  }
  catch (A &) {
    puts("caught A");
  }
}

int main() {
  try {
    throw B();
  }
  catch (A &) {
    reportError();
  }
}

Quick Q: Static constexpr int vs old-fashioned enum: when and why?

Quick A: A static constexpr cannot be used in an ODR context.

Recently on SO:

Static constexpr int vs old-fashioned enum: when and why?

There will be no noticeable difference for integral constants when used like this.

However, enum is actually better, because it is a true named constant. constexpr integral constant is an object which can be, for example, ODR-used - and that would result in linking errors.

#include <iostream>

struct T {
    static constexpr int i = 42;
    enum : int {x = 42};
};

void check(const int& z) {
    std::cout << "Check: " << z << "\n";
}

int main() {
    // check(T::i); // Uncommenting this will lead to link error
    check(T::x);
}

When check(T::i) is uncommented, the program can not be linked:

/tmp/ccZoETx7.o: In function `main': ccc.cpp:(.text+0x45): undefined reference to `T::i' collect2: error: ld returned 1 exit status

However, the true enum always works.

Diagnosable validity -- Andrzej KrzemieĊ„ski

Andrzej Krzemieński wrote down his thoughts on ill-formed C++ code.


Diagnosable validity

by Andrzej Krzemieński

From the article:

Certain combinations of types and expressions can make a C++ program ill-formed. “Ill-formed” is a term taken from the C++ Standard and it means that a program is not valid, and compiler must (in most of the cases) reject it. This is quite obvious:

int main()
{
  auto i = "some text".size(); // invalid expression
};

String literals do not have member functions, therefore compiler cannot accept this program, and must report an error. This puts a responsibility on programmers to learn which expressions and types are valid in a given context and use only these. Again, I am saying a very obvious thing.

What is less obvious is that there is a way in C++ to enter a type or expression of which we do not know if it is valid or not, in an isolated environment, where it does not render the entire program ill-formed, but instead it returns a yes-no (or rather valid-invalid) answer, which we can use at compile-time to make a decision how we want the program to behave. When requested, compiler can analyze all the declarations it has seen so far, and make an approximated judgement whether a given type or expression would make the program ill-formed or not, if used outside the isolated environment. The compiler’s approximated answer is not always correct, but it is just enough most of the time.

 

Quick Q: Templated Function results in Circular Inclusion

Quick A: Separate definition and implementation.

Recently on SO:

Templated Function results in Circular Inclusion

Define registerEvent after IApp.

class IApp;

class Component
{
    IApp* app;
    template<typename T>
    void registerEvent(const int& evtId, Status (T::*func) (int));
};

class IApp : public Component {
  ...
};

template <typename T>
Component::registerEvent(const int& evtId, Status (T::*func) (int)) {
  auto res = std::bind(func, (T*)this, std::placeholders::_1);
  app->registerForEvent(evtId);
}

If need be, also define A::registerEvent after Component::registerEvent.

Quick Q: Why is list initialization (using curly braces) better than the alternatives?

Quick A: It is less likely to generate an unexpected error.

Recently on SO:

Why is list initialization (using curly braces) better than the alternatives?

Basically copying and pasting from Bjarne Stroustrup's "The C++ Programming Language 4th Edition":

List initialization does not allow narrowing (§iso.8.5.4). That is:

  • An integer cannot be converted to another integer that cannot hold its value. For example, char to int is allowed, but not int to char.
  • A floating-point value cannot be converted to another floating-point type that cannot hold its value. For example, float to double is allowed, but not double to float.
  • A floating-point value cannot be converted to an integer type.
  • An integer value cannot be converted to a floating-point type.

Example:

void fun(double val, int val2) {

    int x2 = val; // if val==7.9, x2 becomes 7 (bad)

    char c2 = val2; // if val2==1025, c2 becomes 1 (bad)

    int x3 {val}; // error: possible truncation (good)

    char c3 {val2}; // error: possible narrowing (good)

    char c4 {24}; // OK: 24 can be represented exactly as a char (good)

    char c5 {264}; // error (assuming 8-bit chars): 264 cannot be
                   // represented as a char (good)

    int x4 {2.0}; // error: no double to int value conversion (good)

}

The only situation where = is preferred over {} is when using auto keyword to get the type determined by the initializer.

Example:

auto z1 {99}; // z1 is an initializer_list<int>
auto z2 = 99; // z2 is an int

Conclusion

Prefer {} initialization over alternatives unless you have a strong reason not to.

Top 10 dumb mistakes to avoid with C++ 11 smart pointers -- Deb Haldar

Discussion on various aspect of C++11 smart pointers uses.

Top 10 dumb mistakes to avoid with C++ 11 smart pointers

by  Deb Haldar

From the article:

I love the new C++ 11 smart pointers. In many ways, they were a godsent for many folks who hate managing their own memory. In my opinion, it made teaching C++ to newcomers much easier.

However, in the two plus years that I've been using them extensively, I've come across multiple cases where improper use of the C++ 11 smart pointers made the program inefficient or simply crash and burn. I've catalogued them below for easy reference.

Quick Q: Is this std::ref behaviour logical?

Quick A: Yes, std::ref can be reassigned (see example)

Recently on SO:

Is this std::ref behaviour logical?

A small modification to f2 provides the clue:

template<class T>
void f2(T arg)
{
    arg.get() = xx;
}

This now does what you expect.

This has happened because std::ref returns a std::reference_wrapper<> object. The assignment operator of which rebinds the wrapper. (see http://en.cppreference.com/w/cpp/utility/functional/reference_wrapper/operator%3D)

It does not make an assignment to the wrapped reference.

In the f1 case, all is working as you expected because a std::reference_wrapper<T> provides a conversion operator to T&, which will bind to the implicit right hand side of ints implicit operator+.

Strict Weak Ordering and STL -- Saurabh Singh

Saurabh Singh describes in a brief tutorial on how to correctly implement the comparator function for STL containers and algorithms. 

Strict Weak Ordering and STL

by Saurabh Singh

From the article:

If you had ever used a map or set or even std::sort I bet you would have to give a comparator function. (Or an overload to the < (less than) operator).
I will try to give an overview of how certain associative stl containers use this property for ordering the elements.
Almost all stl containers rely on strict weak ordering A strict weak ordering defines the relative position of elements in terms of precedence of one item over other. For eg. if you have a room full of person and you have to form a queue based on their height, a person with "lesser" height will "precede" the person with greater height. For a function to be satisfying strict weak ordering following conditions need to be met.

The PDF version of the document is available here.