Articles & Books

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.

 

Quick Q: Should I return a const value? -- StackOverflow

Quick A: No.

Some authors wrote "Consider doing this" in C++98. The answer is now a definite "No" because it prevents move from returned values.

Isn't the const modifier here unnecessary?

The "Effective C++" Item 3 says "Use const whenever possible", and it gives an example like:

 

const Rational operator*(const Rational& lhs,
                            const Rational& rhs);

to prevent clients from being able to commit atrocities like this:

Rational a, b, c;
...
(a * b) = c;   // invoke operator= on the result of a*b!

But isn't the non-reference return value of functions allready a rvalue? So why bother doing this?