June 2013

Quick Q: Is atomic decrementing more expensive than incrementing? -- StackOverflow

Quick A: No, not in general. Yes, in the specific case of a reference counted smart pointer which can take advantage of its special semantics.

Is atomic decrementing more expensive than incrementing?

In his Blog Herb Sutter writes

[...] because incrementing the smart pointer reference count can usually be optimized to be the same as an ordinary increment in an optimized shared_ptr implementation — just an ordinary increment instruction, and no fences, in the generated code.

However, the decrement must be an atomic decrement or equivalent, which generates special processor memory instructions that are more expensive in themselves, and that on top of that induce memory fence restrictions on optimizing the surrounding code.

The text is about the implementation of shared_ptr and I am not sure if his remark applies only on this or is generally the case. From his formulation I gather it is generally.

But when I think about it I can only think of "more expensive decrement" when a if(counter==0) immediately follows -- which probably is the case with shared_ptr.

Therefore I wonder if the atomic operation ++counter is (usually) always faster than --counter, or just because it is used if(--counter==0)... with shared_ptr?

Quick Q: What's the difference between lambda [x]()mutable{++x;} and [&x](){++x;}? -- StackOverflow

Quick A: [x] captures a copy, [&x] remembers a reference to the original variable.

C++ Lambdas: Difference between “mutable” and capture-by-reference

In C++ you can declare lambdas for example like this:

int x = 5;
auto a = [=]() mutable { ++x; std::cout << x << '\n'; };
auto b = [&]()         { ++x; std::cout << x << '\n'; };

Both let me modify x, so what is the difference?

GotW #92 Solution: Auto Variables, Part 1 -- Herb Sutter

The solution to the latest GotW problem is now available:

GotW #92 Solution: Auto Variables, Part 1 (updated for C++11/14)

by Herb Sutter

From the article:

When you’re new to auto, the key thing to remember is that you really are declaring your own new local variable. That is, “what’s on the left” is my new variable, and “what’s on the right” is just its initial value:

auto my_new_variable = its_initial_value;

You want your new variable to be just like some existing variable or expression over there, and be initialized from it, but that only means that you want the same basic type, not necessarily that other variable’s own personal secondary attributes such as top-level const-ness and reference-ness which are per-variable. For example, just because he’s const doesn’t mean you’re const, and vice versa.

It’s kind of like being identical twins: Andy may be genetically just like his brother Bobby and is part of the same family, but he’s not the same person; he’s a distinct person and can make his own choice of clothes and/or jewelry, go to be seen on the scene in different parts of town, and so forth. So your new variable will be just like that other one and be part of the same type family, but it’s not the same variable; it’s a distinct variable with its own choice of whether it wants to be dressed with const and/or a reference, may be visible to different threads, and so forth.

Remembering this will let us easily answer the rest of our questions...

Empty List Initialization -- Andrzej Krzemieński

A belated link to Andrzej's recent article:

Empty list initialization

by Andrzej Krzemieński

From the article:

My conclusion from the above story is this piece of advice. When you provide an initializer-list constructor for your class, make sure that you also provide a default constructor with the same semantics as though you were initializing with a zero-size initializer_list.

GotW #91 Solution: Smart Pointer Parameters -- Herb Sutter

The solution to the latest GotW problem is now available:

GotW #91 Solution: Smart Pointer Parameters (updated for C++11/14)

by Herb Sutter

From the article:

 

Guideline: Don’t pass a smart pointer as a function parameter unless you want to use or manipulate the smart pointer itself, such as to share or transfer ownership.

Guideline: Prefer passing objects by value, *, or &, not by smart pointer.

If you’re saying, “hey, aren’t raw pointers evil?”, that’s excellent, because we’ll address that next...

Intuitive Interface, Part 1 -- Andrzej Krzemieński

Good advice from the designer of the new std::optional<T> on how to design modern C++ classes to follow GotW #1's advice to avoid writing initializer_list constructors that force callers to resort to () instead of {} to disambiguate.

Intuitive Interface -- Part I

by Andrzej Krzemieński

From the article:

Let’s start with the popular C++(11) “uniform initialization” gotcha. Changing braces to parentheses in object initialization may change the semantics of the initialization:

 

std::vector<int> v1{5, 6}; // 2 elems: {5, 6}
std::vector<int> v2(5, 6); // 5 elems: {6, 6, 6, 6, 6}

For instance, it is described in Problem 1 of the newly revisited “Guru of The Week” series by Herb Sutter.

When seeing such an example, one might conclude that the new rules for object initialization are very confusing or error-prone. But to me it looks like the problem here lies in how class template std::vector has been defined in C++03...

Quick Q: Doesn't { } initialization guarantee no narrowing conversions? -- StackOverflow

Quick A: Yes, but some compilers have conforming extensions that give meaning to nonportable programs.

Preventing narrowing conversion when using std::initializer_list

#include <iostream>

struct X {
    X(std::initializer_list<int> list) { std::cout << "list" << std::endl; }
    X(float f) { std::cout << "float" << std::endl; }
};

int main() {
    int x { 1.0f };
    X a(1);     // float (implicit conversion)
    X b{1};     // list
    X c(1.0f);  // float
    X d{1.0f};  // list (narrowing conversion) ARG!!!

    // warning: narrowing conversion of '1.0e+0f' from 'float' to 'int'
    // inside { } [-Wnarrowing]
}

Is there any other way of removing std::initializer_list from an overload list (i.e., making the non-list ctors more favorable) instead of using the ()-initialization, or at least prohibiting narrowing conversion to happen (apart from turning warning into error)?

I was using http://coliru.stacked-crooked.com/ compiler which uses GCC 4.8.

 

Scott Meyers in Oslo: Friday, June 14

On Friday, June 14, Scott Meyers will be giving a talk open to the public at the Oslo C++ Users Group.

From Scott's announcement:

Lambdas vs. std::bind in C++11 and C++14

Scott Meyers

 

C++ developers have long had a need to bind functions and arguments together for a later call. This is what makes it possible to invoke member functions on objects inside STL algorithms. The same technology can be used to create custom callback functions and to adapt function interfaces to different calling contexts.

In C++98, such binding was accomplished via std::bind1st and std::bind2nd. TR1 added std::tr1::bind, which was promoted to std::bind in C++11. But C++11 also introduced lambda expressions, and they’re slated to become even more powerful in C++14. That means that there are now two mechanisms in C++ for binding functions to arguments for later calls: std::bind and lambda expressions. In this talk, Scott examines the pros and cons of each approach, comparing them in terms of expressiveness, clarity, and efficiency, and he comes to the conclusion that one should almost always be used instead of the other. But which one?

 

This presentation assumes a basic familiarity with std::bind and C++11 lambda expressions.