
C++11/14 Idioms I Use Every Day - ingve
http://seshbot.com/blog/2014/08/16/modern-c-plus-plus-idioms-i-use-every-day/
======
forrestthewoods
Raarrggghrhghh. I couldn't possibly disagree with his proposed use of 'auto'
more. Abundant use of auto is the opposite of readable! Nothing is more
infurating than jumping into a new bit of the code base and having no idea
what anything is or what it can do.

Auto is acceptable for iterators and, in some cases, references to complicated
containers. Don't fucking type "auto pos" instead of "Vec2i pos", "Vec3f pos",
or one of many other possible types that pos variable may represent.

~~~
lbrandy
Ah yes, the type inference argument. I give the onboarding here for new hires
about C++ and so I get some form of this objection (and the subsequent
argument) every two weeks like clockwork. Here's what I say (feedback
welcome):

1\. Sometimes `auto` helps readability immensely. Sometimes it hurts
immensely.

2\. All generalizations about when and where to use it are generalizations and
likely to start an argument.

3\. Ultimately it's up to you and your diff reviewers to do the right thing.
There will be people reading your code in the future and they will judge you
and your decision, so choose wisely. Future-you included.

4\. `auto` can often improve correctness/generality, not just readability,
e.g. "int sz = v.size(); //BAD". No one writes "vector<int>::size_type sz =
v.size();" I dare you to search your code for it.

5\. The only controversial generalization I feel safe making, knowing saying
it will get me into trouble, is that experienced non-C++11 (whether coming
from C++03 or other languages) coders tend to be more apprehensive and
cautious, using `auto` less than experienced C++11 programmers. Take it for
what it's worth.

~~~
forrestthewoods
1\. Agree

2\. Agree

3\. Agree

4\. I don't use vector<int>::size_type and I don't use decltype(sz) throughout
the rest of the function. I use size_t and let the compiler give me an error
if size() happens to return a different type or, if when making use of sz,
types get mixed.

5\. That's a little too anecdotal and 'appeal to authority' for my liking.

The big question, I suppose, is defining guidelines for when auto helps
readability and when it hurts it. My experience has been that it is best to
default to no auto and only use auto after trying the non-auto way first.
Iterators and template-heavy containers are great instances where auto helps.
In our codebase I can't think of another situation in which auto would be
useful.

We also don't have heavy template usage outside of containers. If your code
has templates everywhere then I can imagine the number of times auto is an
improvement in readability would be larger.

There have been exceptionally few times where I have jumped into someone
else's code and said "wow, their heavy use of auto has made this easier to
read and understand".

~~~
dllthomas
I've no dog in this fight, but narrowly with regard to

 _' There have been exceptionally few times where I have jumped into someone
else's code and said "wow, their heavy use of auto has made this easier to
read and understand".'_

I think it's far easier to notice when you hit unreadable code and what seems
to be making it unreadable, than it is to notice when you hit readable code
and what seems to be making it unusually readable. That's not to say your
conclusions are necessarily wrong (or right), by any means - just that I'd
view this particular argument with an added measure of skepticism.

------
santaclaus
Has anyone taken a look at the new versions of Bjarne Stroustrup's C++
Programming Language [1] or Scott Meyer's Effective Modern C++ [2]? The
originals are classics, and I would be interested to know if the new versions
hold up.

[1] [http://www.stroustrup.com/4th.html](http://www.stroustrup.com/4th.html)
[2]
[http://shop.oreilly.com/product/0636920033707.do](http://shop.oreilly.com/product/0636920033707.do)

~~~
tdicola
I read his short A Tour of C++ and enjoyed it a lot. Much of it is taken from
parts of his update to The C++ Programming Language. If you just want a short
book to introduce the new parts of C++11, A Tour of C++ is the way to go.

------
thebear
Thanks for this blog post; it will help me to make the best use of C++11/14
features in day-to-day programming. One thing I've been wondering about for a
while is how the auto keyword relates to type-safety. The blog post lists the
point "auto type deduction everywhere" under "type-safety". But consider the
line

    
    
      auto x = foo();
    

Suppose you refactor your code, and in the process, the return type of foo()
changes. Without the use of auto, the compiler would produce an error message,
alerting you that the above line of code may need your attention. As it is,
with the use of auto, the above line will compile no matter what. In other
words, that particular line now behaves as if C++ was an untyped language.
Isn't that a step down as far as type-safety is concerned? Please note: I'm
not asking here whether that's good or bad. I'm asking, "Assuming that we use
the auto keyword throughout, can we still call C++ 'strongly typed'"?

~~~
flebron
It's going to be untyped in the same sense that the following Haskell code is
untyped:

    
    
        foo = [1, 2, 3]
        x = foo
    

We didn't give a type to x, but the compiler will infer it anyway. If foo
changes, x will change too. This does not make Haskell untyped, it just means
it can add type annotations by itself in most cases (see Hindley-Milner type
inference).

Note that that code won't "compile no matter what", because in C++
construction using "=" is already an operation that not all types have. So if
foo returns an object which does not have a copy constructor or move
constructor, then that line will fail to compile. In the more general case,
you'll still not be able to use operations on x that x's type does not
support, and that's what type safety means.

~~~
thebear
Ok, I got you. If type-safety means, as you say, "you can only use operations
on x that x's type supports", then all is well. I must admit that I was under
the impression that type-safety meant more: if I assign to a variable x of
type A an object of type B, then that is an error even if the type B will work
syntactically (i.e. has all the operations needed by my variable x), because
it may not work semantically.

~~~
squeaky-clean
>if I assign to a variable x of type A an object of type B

You're correct that this is unsafe, but this isn't what auto does. You'd be
assigning a variable x of type A an object of type A. Then what that code
theoretically changes, you're now assigning variable x of type B an object of
type B. auto just handles all the boilerplate. It will be type safe, it's just
logically incorrect.

For example

    
    
        public int foo()
        {
            return 1;
        }
    
        auto x = foo();
        //is the same as
        int x = foo();
    

And then you change it to this:

    
    
        public float foo()
        {
            return 1.0f;
        }
    
        auto x = foo();
        //is the same as
        float x = foo();
    

In either case you can go on to do stuff like 'float y = x / 10;' Because
they're both valid operators. But there can be logical inconsistencies, like
the integer division problem that will occur if x is an int. Then again, you
probably shouldn't use auto for something as simple as int or float. But 'auto
foobar = new vector<int>;' is a very clear statement, and if you replace
vector with something else, odds are the compiler will throw a fit with any
later methods you attempt to call.

I haven't written C++ in a while, so I hope I didn't butcher the examples too
much. I simply typed them into the comment box.

The definition of type-safe could be extended to mean what you say, it's not
really a term that is set in stone. But I've always used type safety to mean
preventing type-based syntax errors, not semantic errors. If it's more common
to do otherwise, I'd be happy to be corrected.

~~~
dllthomas
You shouldn't use auto for float and int not just because they're simple, but
because they get happily coerced in ways that might break things. I've not
written much C++11, but my intuition would suggest limiting auto to places
where, upon a change, either 1) everything in the dependency chain will change
and work correctly, or 2) anything that can't change correctly will loudly
break at compile time.

------
santaclaus
I'm loving the new pseudo-random number support. In a few lines one can crank
out some Mersenne twister niceness. No more shipping around custom pseudo-
random code, and no more calls to rand that give different results for the
same seed on different platforms!

------
dfan
The nice thing about C++11 is that the designers seem to have actually tried
to increase usability, rather than just maximizing expressivity, which is
usually the case. Features like range-based for and auto make programming much
more pleasant. I program in a functional style in many other languages, but
could never bear to in C++ before because it was so awkward.

~~~
Silhouette
I still wouldn't try to use too many functional idioms in C++ even now. It's
just not a good language for that kind of programming style. For example, from
the "New language features" section of the C++14 Wikipedia page[1], the first
example is generic lambdas, which means we can now write:

    
    
        auto lambda = [](auto x, auto y) {return x + y;};
    

That's progress of a sort, but in Haskell, a language designed to support this
style of programming, it looks like this:

    
    
        lambda = (+)
    

Obviously C++ is slowly being left behind by modern programming language
design and the collective experience of the programming industry over several
decades since C++ was invented. Eventually it will be superseded by other
languages that do support more expressive language features and better
designed standard libraries (which is easy to do with the wisdom of hindsight,
of course -- this is not a criticism of the people who built C++ without the
benefit of that hindsight).

But since we don't yet have any such alternatives that don't also have
significant drawbacks and/or unacceptable run-time performance
characteristics, for the near future C++ is still going to be the first choice
for a lot of projects in the real world. In that respect, closing the
loopholes and fixing the pain points is useful for a lot of people, and very
wisely that seems to be what the standards committee are concentrating on
doing.

[1]
[http://en.wikipedia.org/wiki/C%2B%2B14#New_language_features](http://en.wikipedia.org/wiki/C%2B%2B14#New_language_features)

~~~
dfan
I agree with your example. But, for example, before C++11, if I wanted to do
an even slightly non-trivial map or filter I'd probably do it by hand rather
than write a (C++) "functor" or assemble some function in place with
std::bind1st et al., whereas now I will happily write a simple lambda.

~~~
Silhouette
I agree, but in C++, I probably wouldn't try to wrap that kind of logic up in
a functional programming style with the standard algorithms anyway.

I've read the advocacy and I've considered the arguments many times, and in a
language designed to support those styles I would absolutely agree that using
them is a huge improvement over a raw loop. But in those languages, the
functional style has clear benefits for both readability and maintainability.

Unfortunately, C++ is not such a language and the benefits of trying to
shoehorn that programming style into C++ projects are far from clear, even
with the new lambdas. Therefore, for logic that isn't completely trivial, I
usually still choose to write the loop.

I suspect we actually have quite similar preferences about programming style,
and I don't like that favouring raw loops is the conclusion I've reached.
However, as with some of the libraries using terribly clever template
wizardry, I find sometimes in C++ the medicine is worse than the disease.

------
tdicola
Looks like a great list of handy things from the latest versions of C++. I
think it might have been a non-standard addition before C++11, but I really
like the data() function on vector. It just gives you a pointer to the first
element of the array of data in the vector. Obviously you can shoot yourself
in the foot pretty badly with this, but it's great for interfacing with legacy
C code, etc. that expects to get a pointer of things and length.

~~~
GFK_of_xmaspast
I think you could also have done something like "&(v[0])" to get the same
thing.

~~~
DerekL
Watch out! "&(v[0])" has undefined behavior if v is empty. "v.data()" always
works, besides being more readable.

~~~
robotresearcher
I looked this up:

"Returns pointer to the underlying array serving as element storage. The
pointer is such that range [data(); data() + size()) is always a valid range,
even if the container is empty."

Can someone explain the semantics? If the range is valid for an empty vector,
what does that say about the validity of tge pointer returned? What value will
it have for an empty vector?

~~~
DerekL
On an empty vector, data() can either return a null pointer, or a pointer to
some allocated memory with suitable alignment for that type, but there doesn't
have to be a existing object.

What is the range [ data(), data() + size() ) anyway? It consists of n + 1
iterators. All but the last one can be dereferenced. You can take one iterator
in the range and add or subtract to get another one, as long as you stay in
the range. You can subtract iterators to get a signed integer. You can compare
iterators with all six operators ==, !=, <, >, <= and >=.

For any valid pointer p, null or not, [p, p) is a valid range of length 0. It
has one iterator, p, but you can't dereference it. You can add or subtract 0.
You can subtract p from itself, getting 0. And you can compare it with itself.

------
cheepin
Thanks for this. I've been wanting to pick up a bit more new C++, but haven't
found a lot of great resources.

~~~
shiloa
Agreed.

Following [https://gobyexample.com](https://gobyexample.com) and
[http://rustbyexample.com](http://rustbyexample.com), a
[http://cppbyexample.com](http://cppbyexample.com) kind of site would be quite
useful for people who are familiar with coding and just want to experience
some practical use cases in idiomatic C++ (threading, json parsing, etc).

