/* */ /* */

Monday, August 25, 2014

Upcoming Appearances: 2 Continents, 5 Countries, 8 Cities, Several Topics

Now that work on Effective Modern C++ is approaching completion, it's time to get out and see the world...and give technical presentations. Between September and December, I'll be giving talks in the United States, Germany, England, Poland, and Latvia. Geographically, the European presentations work out this way:
In the USA, I'll be in Bellevue, WA, Cambridge, MA, and Bala Cynwyd, PA.

The topics I'll be addressing are rather varied, including a lot of information about C++11 and C++14, the importance of CPU caches for software performance, general advice on interface design, plus some reflections on thinking about and writing "Effective" books.

You'll find details on all my upcoming presentations at my Upcoming Talks page, e.g., exact dates, locations, and topics. I think all the presentations will be fun, but let me call out two in particular:
  • If you're interested in material from Effective Modern C++, the most comprehensive seminar I'll be giving on that topic will take place on October 7-8 in London.
  • A special attraction of C++ and Beyond in Stuttgart is looking like it might be a full-blown bar brawl between me and Herb Sutter. In recent weeks, he and I have been going back and forth about the wisdom (or lack thereof) of advising people to use pass-by-value in function interfaces. We've exchanged some posts on this topic in comments on my blog and in posts to a Microsoft C++ MVP mailing list, plus there have been some behind-the-scenes email messages, and at this point, having carefully weighed all the facts, it looks like the only thing we fully agree on is that the other person means well, but is terribly misguided. Herb's German may be better than mine (it definitely is), but when it comes to parameter-passing advice, that boy is going down!
I hope to see you in Bellevue, Cambridge (MA), Bala Cynwyd, Stuttgart, London, Wrocław, Riga, or Berlin later this year.

Scott

Wednesday, August 20, 2014

Near-Final Draft of Effective Modern C++ Now Available (plus TOC and sample Item)

Effective Modern C++ is moving closer and closer to reality. This post contains:
  • Information about availability of an almost-final draft of the book.
  • The current (and probably final) table of contents.
  • A link to the I-hope-I-got-it-right-this-time version of my Item on noexcept.
 

Draft Book Availability

A revised and nearly-final manuscript is now available through O'Reilly's Early Release Program and Safari Books Online's Rough Cuts program. The prose still needs to be sanded down a bit, but practically speaking, this is the final stream of words that will make up the book. Remaining tasks include double-checking the code samples, index generation and final formatting (i.e., typesetting), but this should be quite close to what gets published.

I've left the line numbers in for the online drafts, because that makes it easier for people to report errors to me. The really truly honest-this-is-it version of the manuscript is due to O'Reilly in early September, so if you see anything that needs improvement, please let me know by the end of this month!

Probably-Final Table of Contents

Here's the current table of contents. I'm not wild about the title of the final chapter ("Tweaks"), so if you have suggestions for a better title, let me know.
CHAPTER 1  Deducing Types
  Item 1:  Understand template type deduction. 
  Item 2:  Understand auto type deduction. 
  Item 3:  Understand decltype. 
  Item 4:  Know how to view deduced types. 

CHAPTER 2  auto
  Item 5:  Prefer auto to explicit type declarations. 
  Item 6:  Use the explicitly typed initializer idiom when auto deduces 
           undesired types. 

CHAPTER 3  Moving to Modern C++
  Item 7:  Distinguish between () and {} when creating objects. 
  Item 8:  Prefer nullptr to 0 and NULL. 
  Item 9:  Prefer alias declarations to typedefs. 
  Item 10: Prefer scoped enums to unscoped enums. 
  Item 11: Prefer deleted functions to private undefined ones. 
  Item 12: Declare overriding functions override. 
  Item 13: Prefer const_iterators to iterators. 
  Item 14: Declare functions noexcept if they won't emit exceptions. 
  Item 15: Use constexpr whenever possible. 
  Item 16: Make const member functions thread-safe. 
  Item 17: Understand special member function generation. 

CHAPTER 4  Smart Pointers
  Item 18: Use std::unique_ptr for exclusive-ownership resource management. 
  Item 19: Use std::shared_ptr for shared-ownership resource management. 
  Item 20: Use std::weak_ptr for std::shared_ptr-like pointers that can dangle.
  Item 21: Prefer std::make_unique and std::make_shared to direct use of new.
  Item 22: When using the Pimpl Idiom, define special member functions in the
           implementation file.

CHAPTER 5  Rvalue References, Move Semantics, and Perfect Forwarding
  Item 23: Understand std::move and std::forward. 
  Item 24: Distinguish universal references from rvalue references. 
  Item 25: Use std::move on rvalue references, std::forward on universal
           references.
  Item 26: Avoid overloading on universal references. 
  Item 27: Familiarize yourself with alternatives to overloading on universal 
           references.
  Item 28: Understand reference collapsing. 
  Item 29: Assume that move operations are not present, not cheap, and not used. 
  Item 30: Familiarize yourself with perfect forwarding failure cases. 

CHAPTER 6  Lambda Expressions
  Item 31: Avoid default capture modes. 
  Item 32: Use init capture to move objects into closures. 
  Item 33: Use decltype on auto&& parameters to std::forward them. 
  Item 34: Prefer lambdas to std::bind. 

CHAPTER 7  The Concurrency API
  Item 35: Prefer task-based programming to thread-based. 
  Item 36: Specify std::launch::async if asynchronicity is essential. 
  Item 37: Make std::threads unjoinable on all paths. 
  Item 38: Be aware of varying thread handle destructor behavior. 
  Item 39: Consider void futures for one-shot event communication. 
  Item 40: Use std::atomic for concurrency, volatile for special memory. 

CHAPTER 8  Tweaks
  Item 41: Consider pass by value for copyable parameters that are cheap to 
           move and always copied.
  Item 42: Consider emplacement instead of insertion. 
Technical writing archeologists may wish to compare this TOC with the versions I showed on 18 March 2014, 5 April 2013, and 29 January 2013. I told you things would change!

Close-to-Final Item on noexcept

I posted drafts of my Item on noexcept on 31 March 2014 and 4 February 2014, so I felt obliged to show you the final-unless-I've-really-made-a-serious-mistake version. Here it is:
Let me know what you think. You've never been shy before, and I have no reason to think things will be different this time around :-)

Scott


Wednesday, August 13, 2014

Quick Test Needed for Boost.TypeIndex under Clang

I don't have Clang here (Windows ghetto, sorry), and I haven't been able to find an online Clang compiler that has the Boost headers available, so I'd be grateful if somebody would run the following program under Clang with the latest Boost and let me know (as a blog comment, so that people will know that the work has already been done) what the output is.

Thanks.

Scott


#include <iostream>
#include <vector>
#include <boost/type_index.hpp>

template<typename T>
void f(const T& param)
{
  using std::cout;
  using boost::typeindex::type_id_with_cvr;
  // show T
  cout << "T = "
       << type_id_with_cvr<T>().pretty_name()
       << '\n';
  // show param's type
  cout << "param = "
       << type_id_with_cvr<decltype(param)>().pretty_name()
       << '\n';

}

class Widget {};

std::vector<Widget> createVec()
{
  return std::vector<Widget>(5);
}

int main()
{
  const auto vw = createVec();
  if (!vw.empty()) {
    f(&vw[0]);
  }
} 

Thursday, July 24, 2014

Should move-only types ever be passed by value?

[For this post, I'm going to pretend that std::unique_ptr is a type, instead of a template, because the issue being examined is independent of what a std::unique_ptr points to.]

Suppose I want to pass a std::unique_ptr to a constructor, where the std::unique_ptr will be moved into a data member. The std::unique_ptr parameter thus acts as a sink. To the extent that we have enough experience with C++11 for wisdom about it to be conventional, said wisdom seems to be that the std::unique_ptr should be passed by value. In his GotW 91 solution, Herb Sutter argues for it. The High Integrity Coding Standard has it as a guideline. (It cites Herb's article as the source.) In his C++ Reference Guide, Danny Kalev argues for it. Many StackOverflow answers repeat this advice.

But recently Matthew Fioravante brought a StackOverflow question to my attention showing a problem resulting from declaring a std::unique_ptr by-value sink parameter, and later Matthew suggested that sink parameters of move-only types should be passed by rvalue reference. This is a very interesting idea.

Suppose you see this function signature:
void f(SomeType&& param);
What does this tell you about param? The fact that it's an rvalue reference tells you that it's a candidate to be moved from, and the usual expectation is that it will be. In other words, it's a sink parameter. Note that this is completely independent of param's type. Even without knowing anything about SomeType, we can conclude that param is a sink parameter.

If SomeType happens to be std::unique_ptr, nothing changes: param is still a sink. There's no need for a special rule for std::unique_ptrs that tells us to pass them by value to indicate that they're sinks, because we already have a way to unambiguously say that: pass them by rvalue reference.

Going back to the idea of a constructor moving a std::unique_ptr into a data member, this is what the code looks like using pass by value:
class Widget {
public:
  explicit Widget(std::unique_ptr ptr): p(std::move(ptr)) {}

private:
  std::unique_ptr p;
};
Now consider this calling code:
std::unique_ptr up;

Widget(std::move(up));
What's the cost of getting up into p? Well, the parameter ptr has to be constructed, and the data member p does, too. Each costs a move construction, so the total cost is two move constructions (modulo optimizations).

Now consider the same thing using pass by rvalue reference:

class Widget {
public:
  explicit Widget(std::unique_ptr&& ptr): p(std::move(ptr)) {}

private:
  std::unique_ptr p;
};

std::unique_ptr up;

Widget(std::move(up));
Here, only the data member p will be constructed, so the total cost is only one move construction.

Unless I'm overlooking something, passing sink parameters of type std::unique_ptr by value is inconsistent with our usual idiom for expressing the idea of a sink parameter (i.e., to pass by rvalue reference), and it's less efficient, too. My sense is that the conventional wisdom regarding sink parameters of type std::unique_ptr is all messed up.

Which leads to the question: how did it get messed up?  I believe what happened was that people noticed that for maximal efficiency when passing lvalues and rvalues of a particular type that needed to be copied inside the function, you needed to either overload on lvalue references and rvalue references, or you needed to pass by universal reference. Both approaches have problems (overloading doesn't scale to multiple parameters, and universal references suffer from the shortcomings of perfect forwarding, lousy error messages, and sometimes being too greedy). For cheap-to-move types, people found, you can use pass by value with only a modest efficiency loss, and the conventional wisdom, in large part based on a David Abrahams' blog post, "Want Speed? Pass by value", came to embrace that idea.

The thing is, for move-only types like std::unique_ptr, you don't need to worry about dealing with lvalues, because lvalues get copied, and move-only types aren't copyable. So there's no need to overload for lvalues and rvalues, hence no scalability problem for multiple parameters. Which means that the motivations for replacing pass by reference--which is what the conventional wisdom from C++98 always dictated--with pass by value don't exist for move-only types.

My feeling is that Matthew Fioravante may well have hit the nail on the head here: there is no reason to use by-value parameters to express "sinkness" for move-only types. Instead, the usual rule of passing sink parameters by rvalue reference should apply.

The special case of considering the use of pass by value for always-copied parameters really only applies to types that are both copyable and movable, and only in situations where overloading and the use of a universal reference is not desired.

What do you think? Is there ever a time where move-only types should be passed by value?

Scott

Saturday, July 19, 2014

Free Excerpt from Draft EMC++ Now Available

O'Reilly has made the TOC, Introduction, and first chapter ("Deducing Types") from the draft version of Effective Modern C++ available for free download. That's roughly the first 40 pages of the book, including Items 1-4. The PDF is available here.

I hope you enjoy this sample content, but I can't resist reminding you that this is from a draft manuscript. The final version will be better.

As always, I welcome suggestions for how this material can be improved.

Scott

Friday, July 18, 2014

Is the non-pointer syntax for declaring function pointer parameters not worth mentioning?

In my view, one of the most important favors a technical writer can do for his or her readers is shield them from information they don't need to know. One of my standard criticisms of authors is "S/he knows a lot. S/he wrote it all down." (Yes, I know: the "his or her" and "s/he" stuff is an abomination. Please suffer in silence on that. There's a different fish I want to fry in this post.)

I try not to commit the sin of conveying unimportant information, but one of the hazards of spending decades in this business is that you learn a lot. After a while, it can be hard to evaluate what's worth knowing and what's best left unsaid. With that in mind, the current draft of Effective Modern C++ contains this passage (more or less):
Suppose our function f can have its behavior customized by passing it a function that does some of its work. Assuming this function takes and returns ints, f could be declared like this:
     void f(int (*pf)(int));         // pf = "processing function"
It’s worth noting that f could also be declared using a simpler non-pointer syntax. Such a declaration would look like this, though it’d have the same meaning as the declaration above:
     void f(int pf(int));            // declares same f as above

One of my reviewers argues that the second way of declaring a function pointer parameter is not only not worth noting, it's not worth knowing. That means I should omit it. But I find myself reluctant to do that. I like the fact that function pointer parameters can be declared without throwing in additional parentheses and figuring out which side of the asterisk the parameter name has to go on. But maybe that's just me.

So what do you think? Should I jettison the aside about the asterisk-free way to declare the parameter pf, or should I keep it?

Thanks,

Scott

Friday, July 11, 2014

Draft Version of Effective Modern C++ Now Available

A full draft of Effective Modern C++ is now available through O'Reilly's Early Release program and Safari Books Online's Rough Cuts program.

The cover design for the book has changed. I'm the common crane no longer. Now I'm the fruit dove. I'm not sure what to make of this. Is going from common to fruity an upgrade?

My editor explained the reason for the avian switcheroo:
Since we are going full color for the book, the animal on the cover is going to be full color. The common crane isn't super colorful so we are switching to the fruit dove because it is filled with color.
During the early release it will be in black and white and the color will make its appearance soon.
The big information here is that O'Reilly has decided to print the book in full color. That's a first for me, and it means that the print book will display the different colors I originally put into the manuscript with only digital publishing in mind.

Well, the print book might display those colors. I'm not preparing the formatted content for this book. Instead, I'm working on a manuscript into which I put all the logical information that O'Reilly will need to produce the appropriate formatting for the files that will ultimately be used for publication and distribution. These will include PDF, ePub, and Kindle-compatible .mobi. So text in my manuscript that's red or blue or tan may not show up in those colors in the final product.

However, those colors will show up in the Early Release version of the book, because that document is simply a PDF print-out of the manuscript I'm working on. Please don't assume that the Early Release document reflects what the final book will look like. Even if O'Reilly chooses to use the colors I selected, they'll definitely clean up many aspects of the page layout that I designed to be seen only by me and my technical reviewers.

The Early Release book reflects the state of the manuscript as of about six weeks ago. Since then, I've read through the several hundred comments I got from my reviewers. Of the 315 pages in the manuscript, only 91 survived unscathed. That means that over 70% of the pages in the Early Release version have problems (that I know about). Some issues are small, e.g., misspellings or grammatical errors. Others involve important technical shortcomings that I'll have to think hard about how to address. To date, my favorite error report concerns a page in the manuscript where I managed to mis-translate a simple C++14 lambda expression into a corresponding C++11 lambda or call to std::bind in three different ways. I got it wrong. Three times. In three different ways. On one page. 

The draft book is available either as a standalone purchase or though Safari Books Online. At Safari, the book is currently associated with yet a third cover design (a hummingbird), but I believe we're going with the dove. Yet maybe not. I'm less in the loop on this stuff than you might think an author would be.

If you read the draft Items I posted earlier (here and here), you may be disappointed or even alarmed to see that the Items in the Early Release draft are essentially the same as what I posted. Relax. In the past few months, I've been focusing on finishing a full draft of the book, so work on revising existing Items got pushed to the back burner. I'm tending to those burners now, so the final versions of the Items will include changes in my thinking based on the comments I've received. 

I'm a little nervous about making this draft available. My normal modus operandi is to make things as good as I can before I publish them. What you're seeing in this case is a draft that was as good as I could make it before I sent it out for technical review. Based on the comments of my reviewers, I'd say it's not in bad shape, but there are a lot of places (some 70% of them) that need work. If you see opportunities for improvement, feel free to let me know about them, either by using the O'Reilly or Safari online errata reporting mechanisms or by sending me email (smeyers@aristeia.com). I don't expect to have time to respond to or to even acknowledge every report that comes in, but I assure you that I'll read them all and do my best to incorporate them into the final version of the book.

Scott

Wednesday, June 25, 2014

Another New Video

When I recently posted about five new videos, I didn't realize that Yandex had published my 11 June presentation at the Moscow C++ Party. There I gave a talk, "Why C++ Sails When the Vasa Sank," which is almost a bookend for the talk I gave at the D Conference last month.
"Why C++ Sails..." is my attempt to explain why C++, despite its size and complexity, continues to be a successful and important programming language.

My comments at the beginning of the video probably make more sense if you know that I had just been introduced in Russian, which is a language I don't know.

I think the double-wide format Yandex published that shows the speaker on one side of the video and the slides on the other works really well. That's overlooking, of course, that the speaker in this case is me. Yeesh. Talk about a need for a makeover...

I realize that other outlets (e.g., the isocpp.org blog) have already reported the existence of this video, and it's got at least two independent threads at reddit (here and here), but I wanted to hold off announcing it until it had been added to my web site's Online Videos and Past Talks pages, including links to downloadable video and presentation materials. Things have been a bit backed up here, hence the delay.

Scott

Tuesday, June 24, 2014

The Drawbacks of Implementing Move Assignment in Terms of Swap

More and more, I bump into people who, by default, want to implement move assignment in terms of swap. This disturbs me, because (1) it's often a pessimization in a context where optimization is important, and (2) it has some unpleasant behavioral implications as regards resource management.

Let's consider a simplified case of a container that contains a pointer to its contents, which are stored on the heap. I'm using a raw pointer, because I don't want to abstract anything away through the use of smart pointers.
class Container {     
public:
  Container& operator=(Container&& rhs);

private:
  int *pData;           // assume points to an array
};
Implementing the move assignment operator using std::swap, the code looks like this:
Container& Container::operator=(Container&& rhs)
{
  std::swap(pData, rhs.pData);
  return *this;
}
Swapping two pointers calls for three pointer assignments,
template<typename T>
void swap(T& lhs, T& rhs)
{
  auto temp(lhs);
  lhs = std::move(rhs);
  rhs = std::move(temp);
}
so the cost of implementing move assignment using swap is three pointer assignments.

However, if we assume that an empty container has a null pData pointer, move assignment can be implemented using only 2 pointer assignments:
Container& Container::operator=(Container&& rhs)
{
  delete [] pData;
  
  pData = rhs.pData;
  rhs.pData = nullptr;

  return *this;
}
I'm ignoring the delete for now, but we'll get back to it later. At this point, I want to observe that non-swap move assignment performs only 2/3rds the assignments of its swap-based cousin. That's important, because move operations should typically be as efficient as possible. Remember that they're optimizations of copy operations, and if you're not concerned about their efficiency, why not just omit them and let rvalues be copied? My feeling is that the fact that a class author went to the trouble of adding support for move operations is a sign that the author perceives the class to be one where speed is important. If that's the case, it seems unreasonable to pay a premium to put the object being moved from into the state of the target of the assignment when it's cheaper to put the object into a different, but equally valid (typically default-constructed), state. After all, the semantics of move assignment typically don't specify the state of the source object of the move after the assignment has been performed, so if callers can't rely on it having the state of the target object before the assignment, why pay for it?

But back to the delete. Regardless of which move assignment implementation is used, the delete will eventually be performed. If it doesn't take place in the move assignment operator for the object that's the target of the move assignment, it'll probably occur in the destructor of the object that's the source of the move assignment. The cost therefore doesn't vary between the implementations, but when you incur that cost does, and that can be important.

Suppose that Container objects typically use a lot of memory--enough that you have to worry about it. Now consider the following scenario:
{
  Container c1, c2;
  ...
  c1 = std::move(c2);
  ...
}
In the non-swap implementation of move assignment, c1's memory is released at the point of the assignment, but in the swap version, that memory becomes associated with c2, and the memory may not be released until the end of the scope. That might well surprise the caller, who could hardly be blamed for thinking that when an assignment was made to c1, c1's old resources would be released. And it could certainly increase the maximum amount of memory used by the application at any given time.

In my experience, the impact of move-assignment-by-swap on the timing of resource release isn't as well known as it should be, even though the issue was well described many years ago (e.g., Thomas Becker  here and David Abrahams here).

Now, bear in mind that I said at the outset that I was disturbed by people who, by default, want to implement move assignment in terms of swap. I have no issue with developers who, consciously aware of the performance and behavioral implications of move-assignment-via-swap, choose to use it anyway. For some types, it may be a perfectly valid implementation choice. My concern is that it's gaining a reputation as the way to implement move assignment, and I don't think that's good for C++.

Am I mis-analyzing the situation?

Scott

Effective Modern C++ Status Report

In recent days, two major milestones for Effective Modern C++ have been achieved.  First, I sent a draft of the book's Introduction out for technical review. That was the last part of the book to be written, so I finally have a full draft manuscript. Second, I received an image of the book cover from my publisher, so I now know what the book will look like. My editor informs me that I'm the common crane, which elicited the same response from me and my wife: "common?!"

Working with O'Reilly is new for me. My past C++ books were published by Addison-Wesley, and my relationship with AW continues (both for past books as well as for books in my Effective Software Development Series). For Effective Modern C++, however, I concluded that O'Reilly was a better fit for me, and I'm quite pleased to be working with them.

A complete draft manuscript and a front cover design do not a book make. There's still a lot of work to be done, and I thought you might be interested in the schedule for it:
  • Now until July 31: I revise the manuscript to take comments from my technical reviewers into account. I currently have over 70 reviewer email messages (some extremely long and detailed) waiting to be processed, and I expect that number to increase significantly by the end of this month, which is when I've requested that reviewers get me their remarks.
  • August 1-15: I produce the book's index. This is my least favorite part of book creation, and I warn my wife well in advance that I'll be unusually irritating to be around during this time. Coming up with terms to index, including text rotations (e.g., "universal references, versus rvalue references," "rvalue references, versus universal references," "references, rvalue vs. universal") and page ranges is tedious, at best, and the tools available to get this information into a manuscript (e.g., into Microsoft Word, which is what I'm using) are primitive to the point of sadistic. There are professional indexers, but my experience (as well as that of other authors I know) has been that if you want a useful index for a book on C++, the content has to be created by the author. How practical it would be to have me identify the content and somebody else do the entry into the manuscript, I don't know. Index preparation is highly iterative, so the process would be more collaboration than hand-off, and my one prior experience with index collaboration did not go well.
  • August 16-30: A copyeditor goes over the entire book, looking for errors and inconsistencies in grammar, spelling, style, labeling, and more. No matter how clean you think your manuscript is and no matter how many people you've had review it, getting it back from a copyeditor is always a humbling experience.
  • September 1-5: I edit the manuscript one last time, taking the copyeditor's comments into account.
  • September 5: I deliver a final manuscript to O'Reilly. 
  • Early October: Digital versions of the book become available.
  • Late October: Print versions of the book become available.
If you're dying to see what's in the book, and you don't mind dealing with a manuscript that's in draft form (and hence contains technical errors, awkward prose, Item titles in need of revision, primitive diagrams, confusing explanations, and, I hope, some stuff in decent shape), Effective Modern C++ will be part of O'Reilly's Early Release Program, meaning you'll have a chance to see the book in the same form as my technical reviewers. You'll also be able to offer comments on it. As things stand now, the book is slated to be available in Early Release form the week of July 7th.


And now, if you'll excuse me, I have hundreds of reviewer comments to process...

Scott

Saturday, June 21, 2014

Five New Videos

It seems that every place I go these days, people are pointing a camera at me and pressing Record. As a result, there are five new videos available at my Online Videos page:
Happy video viewing!

Scott

Monday, April 21, 2014

Three Worthwhile std::enable_if Blog Posts

As I continue my work on Effective Modern C++, I'm pleased to see that the pile of stuff I need to read or reread (or reread again), because it might be useful in the book, is getting smaller. Today I finished my second full draft of my chapter on rvalue references, move semantics, and perfect forwarding, and part of that process was reviewing some interesting blog posts that appeared at Flaming Dangerzone. All address std::enable_if, in one way or another. My first draft of the chapter discussed std::enable_if, but for the second draft, I was pleased to get rid of the material, because (1) it's hard to explain, (2) I think it's too advanced and specialized for the kind of book I want to produce, and (3) I think I found a better way to solve the problem I'd been using std::enable_if for. (To be more precise, I believe that a better way was suggested by one of the technical reviewers of the initial draft of that chapter.)

Book or no book, the blog posts were interesting in a "template metaprogramming makes my head hurt" kind of way, so if you like that kind of headache, would like to better understand std::enable_if and its applications, and have not seen these articles, I recommend them:

Remastered enable_if
To SFINAE or not to SFINAE
Beating overload resolution into submission

Scott

Monday, April 14, 2014

"Hello, World" Podcast with Me


Shawn Wildermuth's Hello World Podcast consists of interviews with developers, authors, speakers, etc., about their programming roots, and recently he asked me to participate. If, for some inexplicable reason, you're interested in hearing about how I played teletype-based computer games in the early 1970s, how I took umbrage when told my programming resembled FORTRAN when it should have been BASIC, and how I came to write Effective C++, have a listen.


Scott

Monday, March 31, 2014

Declare functions noexcept whenever possible?

In the comments following my last post, there was some controversy regarding the wording of my advice on noexcept functions. My advice is "Declare functions noexcept whenever possible." Some people appear to be concerned that this could be misconstrued as advocating noexcept even when it makes no sense, but I think the advice is a reasonable conclusion to the Item that supports it. I posted a draft version of that Item in early February, but I've revised the draft since then, and I'm making the current draft available now:

The current draft of "Declare functions noexcept whenever possible."

I'd be interested to hear what you think of (1) the wording of the Item title and (2) the contents of the Item itself. I'd also be interested to know what you think about these questions:
  • Should I say that constexpr functions are normally good candidates for noexcept?
  • Do lambdas get special consideration, or should they, too be declared noexcept whenever possible. If they're special, why?
  • Do inline functions get special consideration, or should they also be declared noexcept whenever possible? If they're special, how so?
Please let me know what you think.

Thanks,

Scott

Tuesday, March 18, 2014

Book Report: New Title, New TOC, New Sample Item

The purpose of this post is to update you on the status of the book I'm working on. It includes a new working title, a revised table of contents and a new draft sample Item.

Thanks to comments on my blog post asking for suggestions about how to name the book, I've changed the working title to Effective Modern C++, and I've accustomed myself to distinguishing the abbreviation EMC++ (the current book) from MEC++ (More Effective C++). Sharp-eyed readers may have noticed that the new title has already appeared on a talk I'll be giving in June at the Norwegian Developers Conference.

I recently finished the 32nd Item for the book, thus giving me drafts of five full chapters. The math still shows that about 40 Items will fit in the book's allotted 300 pages, so yesterday I took a hatchet to the prospective table of contents and chopped the number of Items down from 51 to 41. (Why 41? Because I have a feeling that one of the Items I've written will eventually get jettisoned as not being important enough to make the final cut.)  Here's the current draft TOC. The chapters I've written are 1-4 and 6 (i.e., chapters 5 and 7 remain on my todo list).

Chapter 1 Deducing Types
  Item 1: Understand template type deduction.
  Item 2: Understand decltype.
  Item 3: Know how to view deduced types.

Chapter 2 auto
  Item 4: Prefer auto to explicit type declarations.
  Item 5: Remember that in variable declarations, auto + { expr }
          yields a std::initializer_list.
  Item 6: Be aware of the typed initializer idiom.

Chapter 3 From C++98 to C++11 and C++14
  Item 7: Distinguish () and {} when creating objects.
  Item 8: Prefer nullptr to 0 and NULL.
  Item 9: Prefer alias declarations to typedefs.
  Item 10: Prefer scoped enums to unscoped enums.
  Item 11: Prefer deleted functions to private undefined ones.
  Item 12: Declare overriding functions override.
  Item 13: Prefer const_iterators to iterators.
  Item 14: Use constexpr whenever possible.
  Item 15: Make const member functions thread-safe.
  Item 16: Declare functions noexcept whenever possible.
  Item 17: Consider pass by value for cheap-to-move parameters that
           are always copied.
  Item 18: Consider emplacement instead of insertion.
  Item 19: Understand special member function generation.

Chapter 4 Smart Pointers
  Item 20: Use std::unique_ptr for exclusive-ownership resource
           management.
  Item 21: Use std::shared_ptr for shared-ownership resource
           management.
  Item 22: Use std::weak_ptr for std::shared_ptr-like pointers that can
           dangle.
  Item 23: Prefer std::make_unique and std::make_shared to direct use
           of new.
  Item 24: When using the Pimpl Idiom, define special member
           functions in the implementation file.

Chapter 5 Lambda Expression
  Item 25: Avoid default capture modes.
  Item 26: Keep closures small.
  Item 27: Prefer lambdas to std::bind.

Chapter 6 Rvalue References, Move Semantics, and Perfect Forwarding
  Item 28: Understand std::move and std::forward.
  Item 29: Distinguish universal references from rvalue references.
  Item 30: Pass and return rvalue references via std::move, universal
           references via std::forward.
  Item 31: Avoid overloading on universal references.
  Item 32: Understand alternatives to overloading on universal
           references.
  Item 33: Understand reference collapsing.
  Item 34: Assume that move operations are not present, not cheap,
           and not used.
  Item 35: Familiarize yourself with perfect forwarding failure cases.

Chapter 7 The Threading API
  Item 36: Make std::threads unjoinable on all paths.
  Item 37: Specify std::launch::async if asynchronicity is essential.
  Item 38: Be aware of varying thread handle destructor behavior
  Item 39: Consider void futures for one-shot event communcation.
  Item 40: Reserve std::atomic for concurrency, volatile for memory-mapped
           I/O.
  Item 41: Employ sequential consistency if at all possible.

You may want to compare this to the initial preliminary TOCs I posted here and here to confirm that I wasn't kidding when I said that things would change. Things might change in the above TOC, too, but this one will be a lot more stable than the earlier versions.

The most recent Item I wrote was "Distinguish () and {} when creating objects." I blogged about one aspect of this topic here, and I thought you might be interested to see what I came up with. I've therefore made the current draft of this Item available, and I welcome your comments on it. Like almost all Items I've written, it's too long, so I'm especially interested in suggestions on how I can make it shorter, but I welcome all suggestions for improvement.

As things stand now, I'm hoping to have a full draft of the book by the end of April. We'll see how it goes.

Scott

Upcoming Public Presentations

2014 is shaping up to be a year with more public presentations than usual. As always, you can find links to all my scheduled talks at my Upcoming Talks page, but here are the ones scheduled so far:

On May 22, I'll giving a keynote address at the D Conference, The Last Thing D Needs. That'll take place in Meno Park, CA. I'm deliberately publishing no description of this talk, because I'd like to maintain the air of mystery engendered by the organizers' asking me to give a talk at conference on a programming language other than the one I'm normally associated with :-)

On June 4, I'll be giving four talks in Oslo at the Norwegian Developers Conference. They're introducing a C++ track this year, and two of my talks will be part of that: Effective Modern C++ and C++ Type Deduction and Why You Care. Of the other two, one will be on interface design (Better Software--No Matter What: The Most Important Design Guideline), and the other will be on performance (CPU Caches and Why You Care).

On September 17, I'll again present CPU Caches and Why You Care, this time in Bala Cynwyd, PA (near Philadelphia). That will be an evening presentation sponsored by Susquehanna International Group.

On October 7-8, I'll be doing a two-day seminar in London for Learning Connexions on material taken from the book I'm currently working on. The seminar is Effective C++11/14 Programming.


There are other presentations in the planning stages, so there will be more to come. To keep in the loop, stay tuned to this blog or do a periodic fly-by of my Upcoming Talks page.

I hope to see you at one or more of these presentations.

Scott

Thursday, March 13, 2014

A Concern about the Rule of Zero

The Rule of Zero, coined, as far as I know, by R. Martinho Fernandes in this blog post, is:
Classes that have custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership. Other classes should not have custom destructors, copy/move constructors or copy/move assignment operators.
By "not have," Martinho really means "not declare", because all classes have destructors, one way or another, and the blog post makes clear that Martinho expects a non-resource-handling class to have the copying and moving behavior exhibited by its data members (and hence to have the corresponding functions, assuming such functionality is employed). If we revise the wording of the rule in accord with s/have/declare/g, we get:
Classes that declare custom destructors, copy/move constructors or copy/move assignment operators should deal exclusively with ownership. Other classes should not declare custom destructors, copy/move constructors or copy/move assignment operators.
This advice makes me a bit uncomfortable.

In concept, it's great. Morally, I'm on board. I agree that classes that don't manage resources should be designed so that the compiler-generated functions for copying, moving, and destruction do the right things. I'm just not sure that taking advantage of that by not declaring any of these functions is a good idea.

Consider a class Widget that doesn't do resource management. Per the Rule of Zero, it declares none of the five special functions covered by the rule. Further assume that its data members are both copyable and movable. Widget objects are therefore copyable and movable, too.
class Widget {
public:
  ...                // no dtor or copy or move functions
};
Wonderful. Life is good.

Now assume something in the software doesn't work the way it should. It could be a behavioral problem (i.e., your run-of-the-mill bug) or it could be a performance problem. Either way, debugging ensues. Let's assume that during debugging, it becomes convenient to temporarily add a destructor to do something like produce a log message for tracing purposes:
class Widget {
public:
  ~Widget();         // temporary destructor
  ...                // no copy or move functions
};
The addition of the destructor has the side effect of disabling generation of the move functions, but because Widget is copyable, all the code that used to generate moves will now generate copies. In other words, adding a destructor to the class has caused presumably-efficient moves to be silently replaced with presumably-less-efficient copies. That strikes me as the kind of thing that (1) is likely to surprise people and (2) could really complicate debugging. Hence my discomfort.

I'm inclined to recommend that a better way to rely on the compiler-generated copy and move functions is to expressly say that they do the right thing--to define them via =default:
class Widget {
public:
  Widget(const Widget&) = default;
  Widget(Widget&&) = default;

  Widget& operator=(const Widget&) = default;
  Widget& operator=(Widget&&) = default;

  ...
};
With this approach, the spirit of the Rule of Zero remains: classes that don't manage resources should be designed so that the compiler-generated functions for copying, moving, and destruction do the right things. But instead of expressing this by not declaring those functions, it's expressed by declaring them explicitly and equally explicitly opting in to the compiler-generated implementations.

What do you think? Does this advice make sense? Should the Rule of Zero perhaps be the Rule of the Five defaults?

Thanks,

Scott

Saturday, March 8, 2014

If braced initializers have no type, why is the committee so insistent on deducing one for them?

I'm one Item away from having five full draft chapters for my book on effective use of C++11 and C++14. That's one Item away from being about 75% done. I'd really like to get that Item behind me.

The prospective Item title is "Distinguish () and {} when creating objects." I've put off writing it for months, because, frankly, I think the technical situation is a mess, and the advice I have isn't as helpful as I'd like. There are a number of aspects to the mess, but part of the problem is that a braced initializer such as "{ 10, 20, 30}" has no type, yet the C++11 and C++14 standards insist on deducing one for it. But only sometimes. Not always. Not for template arguments. Not for function return types. Not for auto parameters to lambda expressions. Only for auto variables. Which is why this is the case:

auto x = { 5 };    // "{ 5 }" has no type,
                   // but x's type is std::initializer_list

In this area, the standard makes no distinction between copy initialization (using "=", as in the example above) and direct initialization (without "=", as in the example on the next line), so:

auto y { 5 };      // y's type is also std::initializer_list

I've never understood why there's a special type deduction rule for braced initializers in the context of an auto variable, but, hey, I'm just a grunt on the ground. My job isn't to make the rules, it's to report them. 

There's an Item in my draft book devoted to the interaction of auto variables and braced initializers, because that interaction confuses everybody. Even so-called experts like me and Herb Sutter have known the thrill of publishing blog posts with incorrect code, because we forgot that 

int x1 = 5;
int x2(5);
int x3{ 5 };
int x4 = { 5 };

all do the same thing, but

auto x1 = 5;       // deduced type is int
auto x2(5);        // deduced type is int
auto x3{ 5 };      // deduced type is std::initializer_list
auto x4 = { 5 };   // deduced type is std::initializer_list

don't.

The committee is not unaware of this issue. The abstract for N3681 says, "This paper proposes to change a brace-initialized auto to not deduce to an initializer list..." That is, it proposes getting rid of type deduction for a construct that doesn't have a type and thereby eliminating a provision of C++ that confuses everybody. (As you can probably tell, I'm in favor of this proposal.)

The successors to N3681, N3912 and N3922, propose getting rid of this behavior only for direct initialization, thus introducing, in my view, even more confusion into an area that already has plenty. Under the proposed new rules, this would be the situation:

auto x1 = 5;      // deduced type is int
auto x2(5);       // deduced type is int
auto x3{ 5 };     // deduced type is int
auto x4 = { 5 };  // deduced type is std::initializer_list

Can somebody please explain to me why it' s so important to have a special rule for deducing a type for a braced initializer list for auto variables using copy initialization, but not important enough for auto variables using direct initialization, auto parameters to lambda expressions, or auto function return types?


Scott

Tuesday, February 18, 2014

Help me name my book

The book I'm currently working on is about the effective use of features new to C++11 and C++14. It covers nothing that's in C++98, other than brief descriptions where they're needed for context. The book consists of entirely new material; nothing is repeated from Effective C++, More Effective C++, or Effective STL. One of the questions I have to answer is what to call this book.

Originally, it was going to be called Effective C++11, but then I decided to cover both C++11 and C++14. My working title is Effective C++11/14, but I'm not terribly happy with that. First, there's no such thing as C++11/14. Second, I'm concerned that by 2015, a book with C++11 in the title will look outdated. On the other hand, I worry that if I call it Effective C++14, many people will assume that it has nothing in it for them if they're "only" using C++11.

An ideal title would convey these points:
  • The content is about the effective use of features new to C++11 and C++14. It doesn't rehash information about C++98, even if it continues to be valid. (For more on this, see my blog entry about the information in Effective C++, Third Edition in the post-C++98 era.)
  • The C++14 material was designed in from the outset, it wasn't just stapled onto a C++11 book as an afterthought.
  • The book isn't a new edition of Effective C++. It complements Effective C++, it doesn't supersede it.
Of course, there will be a description of the book's role and content in its marketing materials, but experience has shown that people often make assumptions about the content of books based on the title and author. Once they've made those assumptions, it generally takes a lot more than a couple of descriptive paragraphs to dislodge misconceptions. It's best for everybody if people's assumptions are correct at the outset.

My plan is to continue my tradition of using a short title that begins with "Effective", plus a longer subtitle. The title can't be "Effective C++," because that's a different book. Here are two possibilities:
  • Effective C++11/14: n Specific Ways to Improve Your Use of the Newest Versions of C++
  • Effective C++14: n Specific Ways to Improve Your Use of C++11 and C++14

What do you think? What should I call the book I'm supposed to be working on as I'm writing this blog entry? What title would be, you know, most effective? (It need not be one of the two I listed above.)

Thanks,

Scott


Tuesday, February 4, 2014

Status Report on Effective C++11/14

About a year ago, I blogged, "If everything falls into place the way I hope it will, there will be a book about 10 months from now. If. I'm not making any promises." Smart me: it's been 12 months, and there's still no book. In part, that's because I decided to expand the scope of the project to encompass C++14 as well as C++11. That required that I familiarize myself with C++14, which has only recently really settled down. Another factor is that writing the Items for the book has proved to be slower going than I expected. I thought my researching days were behind me, but I've spent many more days tracking down language details than I'd predicted.

But I've made progress. I have full drafts of 26 Items, and I have a candidate list of 25 more. Most of the candidate Items won't make the final cut, because it's looking like the book will end up with around 40 Items total. That's due to space limitations. My prior books have run up to around 90,000 words total (about 300 pages) , and that's the length limit I'm imposing on this one.I currently have about 54,000 words, so by that measure, I'm about 60% done. That's a high estimate of how much is complete, unfortunately, because feedback I've received on existing Items reveals that some require significant rework before they'll be ready to be reviewed again.

As things stand now, I'm thinking I should be done by the beginning of June. (Between now and then, writing the book is essentially my full-time job.) "Done" is a funny word, however, because it simply means I've declared my manuscript ready to publish. That's step one in a multi-step process that ultimately leads to printed and digital books. My document has to be translated from the format I use (MS Word) into its final forms (probably print PDF, digital PDF, ePub, and Kindle), and along the way it may get translated into XML as an intermediary format. I'll spare you the details, but suffice it to say that these translations will be largely custom-made for my book, and that means they'll take time to develop and verify. I won't be doing them myself, though I'll be quite involved in making sure they produce the proper output.

I'm hoping that digital versions of the book will be available this summer, but don't press me on exactly what "summer" means. Print books will probably take a bit longer, so call my hope for availability "late summer,"  where neither "late" nor "summer" is well-defined.

In case you're interested in a glimpse into the process of writing this book, I've made available two versions of the Item I finished writing just today, "Declare functions noexcept whenever possible."
  • A first draft with my comments on it. My usual approach to producing an Item is to write and edit it on-screen until it looks decent, then print it out and mark it up, and finally make the edits I've marked. I then print it again, mark it up again, and...rinse, lather, repeat. Generally, it takes about three iterations before I think I've got something ready for the next step, which is to make sure the code compiles. After fixing any simple coding errors, I forward the Item to outside reviewers for their feedback. If the code has errors that are serious enough to affect the content of the Item, I do the necessary rewrite, then fall back into the print/markup/edit loop.
  • The reviewable draft, i.e., the document I've just sent to some outside reviewers for their comments. In this case, that includes you. Feel free to email me your comments and suggestions for improvement, or post them as comments on this blog post.
At some point later, I'll post the current status of the table of contents. Given that I'm going to have to jettison a large number of Items in the current outline, I don't see the point in doing that now. I'll do it once I have a list that looks more stable.

And now, if you'll excuse me, I have a word processor waiting for me...

Scott

Monday, February 3, 2014

Capture Quirk in C++14

Consider this code, which is legal and has the same behavior in both C++11 and C++14:
  const int ci = 42;
  auto f = [ci]() mutable { std::cout << ci << '\n'; };
  f();      // prints 42
This captures the local variable ci by value, thus putting a copy of it inside f. What's interesting is that because ci is const, the copy of it is const, too. That means that attempting to modify the copy of ci inside f won't compile:
  const int ci = 42;
  auto f = [ci]() mutable
           { std::cout << ++ci << '\n'; };      // error! can't modify
                                                // copy of ci that's in f
I wrote about this a couple of years ago in my article, Appearing and Disappearing consts in C++.

Yawn, old news. I know. But C++14 has generalized lambda captures, which means that another way to capture ci by value is this:
  const int ci = 42;
  auto f = [ci = ci]() mutable                  // note revised capture mode
           { std::cout << ++ci << '\n'; };      // okay! copy of ci in f is non-const!
The spec for such captures says that the type of the variable being initialized (the left-hand ci) is determined by the rules used by auto, and auto ignores the constness of initializing expressions when a non-reference, non-pointer is being initialized. So when ci is captured by value using this syntax, the copy inside f isn't const. (This assumes that the lambda is mutable, as it is here. For an explanation of why, I'll again refer you to Appearing and Disappearing consts in C++.) So with C++14, we have two ways to capture a local variable by value: non-generalized and generalized. Non-generalized, which is valid in C++11 and C++14, retains the constness of the variable being captured in the type of the copy. Generalized, which is valid in C++14 only, discards the constness of the variable being captured in the type of the copy. To top things off, we have two syntaxes for non-generalized capture: implicit and explicit. Hence the choices for capturing ci by value are:
  const int ci = 42;
  auto f1 = [=]() mutable                      // non-generalized implicit copy
            { std::cout << ++ci << '\n'; };    // error! copy of ci in f is const

  auto f2 = [ci]() mutable                     // non-generalized explicit copy
            { std::cout << ++ci << '\n'; };    // error! copy of ci in f is const

  auto f3 = [ci = ci]() mutable                // generalized copy
            { std::cout << ++ci << '\n'; };    // fine, copy of ci in f is non-const
Personally, I was never wild about the const retention in non-generalized captures, so I'm pleased that in C++14, there's a way to work around it.

Scott

PS - For the terminally curious, the behavior I'm referring to is specified in 5.1.2/15 for non-generalized captures and 5.1.2/11 for generalized captures (in N3797, the current draft for C++14).

Tuesday, December 24, 2013

ThreadRAII + Thread Suspension = Trouble?

Topic 1: An RAII class for std::thread objects

In my GoingNative 2013 talk, I explained how destruction of joinable std::thread objects leads to program termination, and I introduced an RAII class, ThreadRAII, to make sure that joinable std::threads aren't destroyed. The details of ThreadRAII aren't important for this post, so here's a stripped-down version that always does a join before permitting a joinable std::thread to be destroyed:
class ThreadRAII {
public:
  ThreadRAII(std::thread&& thread): t(std::move(thread)) {}
  ~ThreadRAII() { if (t.joinable()) (t.join(); }

private:
  std::thread t;
};
Using an RAII class to make sure that a std::thread object is brought into an unjoinable state on every path out of a block seems like an obviously-reasonable thing to do.

Topic 2: Using void promises/futures to "start threads suspended"

This Q&A at StackOverflow explains why it might be useful to start threads in a suspended state. There's no direct support for that in the C++11 threading API, but one way to implement it is to create a std::thread running a lambda that waits on a std::future<void> before starting its real work. For example, if the "real work" is funcToRun, we could do this:
std::promise<void> p;

std::thread t([&p]{ p.get_future().wait();    // start t and  suspend it
                    funcToRun(); }            // (conceptually)
              );

...                      // t is "suspended" waiting  for p to be set

p.set_value();           // t may now continue
This isn't the only way to suspend thread execution after creation of the thread and before execution of the work it's supposed to do, but it seems reasonable. In contrast to having the lambda spin on an atomic bool waiting for the flag to be set, for example, there is no need for the lambda to poll.

Putting the two together

The use of a std::thread object in that last code example leads to the possibility of there being some flow of control that could cause that object to be destroyed in a joinable state, and that would lead to program termination. So it seems natural to use RAIIThread:
std::promise<void> p;                         // as before

std::thread t([&p]{ p.get_future().wait();    // as before
                    funcToRun(); }
             );             

ThreadRAII tr(std::move(t));                  // USE RAII CLASS HERE

...                                           // as before

p.set_value();                                // as before
The problem is that if an exception is thrown in the "...", we'll never set the value of the std::promise, and that means that the destructor of the RAII object (tr) will block forever. That's no better than program termination, and it might be worse.

My question

I'm trying to figure out what the fundamental problem is here. Is there something wrong with using an RAII class to keep joinable threads from being destroyed (hence causing program termination)? Is there something wrong with using void promises/futures to emulate starting thread execution in a suspended state?

If the two techniques are independently valid, am I combining them incorrectly, or are they somehow fundamentally incompatible?

I'd like to write about this in Effective C++11/14, but I want to offer my readers good advice. What should that advice be?

Thanks,

Scott


Thursday, September 12, 2013

My 1999 CD on Modern Browsers

In 1999, Addison-Wesley and I collaborated on a CD version of two of my books, Effective C++, Second Edition and More Effective C++. The CD was designed for contemporary browsers--contemporary to 1999. That was a time of rapid browser evolution, and it wasn't too long before browsers "progressed" to the point where the CD content didn't display correctly.

In 2003, Ian Roberts described how the content could be modified to work with IE6, and I published a program to apply his fixes to the files on the CD.

A few days ago, I got a message from Yong-guang Teng telling me that he'd come up with a shell script that permits the CD content to display better on current browsers. He's posted the script as a comment at the Amazon product page for the CD. Be sure to check the comment on his comment, because it tries to compensate for some text-mangling that apparently took place during Amazon's processing of his script text.

I haven't tested his script, so I don't know how well it works. And I don't advocate you buy a copy of the CD, because even if the content can be made to display perfectly with modern browsers, the content itself is still nearly 15 years old, and the second edition of Effective C++ has been superseded by the third edition. Still, Yong-guang Teng found it useful to breathe new life into the CD he bought many years ago, and perhaps you will, too.

Scott

Monday, September 9, 2013

"An Effective C++11/14 Sampler" Now Online

My talk from last week's Going Native 2013 conference, "An Effective C++11/14 Sampler" is now online. It covers these three guidelines:
  • Understand std::move and std::forward.
  • Declare functions noexcept whenever possible.
  • Make std::threads unjoinable on all paths.
Watch it here and let me know what you think.

Scott

Wednesday, August 21, 2013

Sale on AW C++ Books


The pepped-up marketing folks at Addison-Wesley recently sent me this, which I am dutifully passing on:
Please feel free to point folks to informit.com/cplusplus which features a Buy 1 Save 30% | Buy 2 or More Save 40% discount code for all C++ titles.  Note, while only the most recent C++ titles are featured on the landing page, the discount code applies to ALL titles (there is a giant "Shop all C++ Titles" button at the bottom of the page and folks can search for your products by your last name).
According to the banner at the top of the page, the deal also includes free ground shipping within the USA. To get the discounts, you have to enter the magic promotion code CPLUSPLUS at checkout.

Happy shopping!

Scott

Friday, August 2, 2013

Two videos coming, many videos past

On September 4-6, the 2013 edition of GoingNative will take place, and I'll be giving the following presentation:

An Effective C++11/14 Sampler

After years of intensive study (first of C++0x, then of C++11, and most recently of C++14), Scott thinks he finally has a clue. About the effective use of C++11, that is (including C++14 revisions). At last year’s GoingNative, Herb Sutter predicted that Scott would produce a new version of Effective C++ in the 2013-14 time frame, and Scott’s working on proving him almost right. Rather than revise Effective C++, Scott decided to write a new book that focuses exclusively on C++11/14: on the things the experts almost always do (or almost always avoid doing) to produce clear, efficient, effective code. In this presentation, Scott will present a taste of the Items he expects to include in Effective C++11/14. If all goes as planned, he’ll also solicit your help in choosing a cover for the book.

Like all the talks at GoingNative, mine will be live-streamed as well as recorded for later viewing. But it occurred to me a while ago that although my web site has a list of my past publications and my past presentations, it doesn't really have a list of videos of presentations I've given. Well, it didn't. It does now: check out my brand spanking new online videos page. If the thought of such a page moves you to nominate me for the Personal Vanity Hall of Shame, I understand, but my actual motivation was considerably more pedestrian. It's not uncommon for me to be asked whether my presentations are available online, and now there's an easy way for people to answer that question themselves.

Which reminds me. I presented my seminar, Better Software—No Matter What, at the Norwegian Developers Conference in June, and most of that talk has now been made available online. The original plan was for the entire thing to be recorded, but there was a technical glitch that prevented the first of six parts from being preserved. Parts 2-5 are now live, and when the NDC tells me where part 6 is, I'll add a link to that, too.

Scott

PS - Speaking of Effective C++11/14, just today I finished my first full draft of the chapter on rvalue references, move semantics, and perfect forwarding. It consists of eight Items and, if Microsoft Word is to be believed, 20,359 words. Assuming 90K words for the full book (in line with my past efforts, if FrameMaker is to be believed), that means I'm a bit over 20% of the way towards a full draft.

Wednesday, July 24, 2013

Video for "The Universal Reference/Overloading Collision Conundrum"

Last Wednesday evening, I gave a talk at the Northwest C++ Users' Group entitled "The Universal Reference/Overloading Collision Conundrum." The purpose of the talk was to try out the information behind a guideline from Effective C++11/14 (the book I'm currently working on).  That guideline is "Avoid overloading on universal references." The video for that talk is now available.

From my perspective, the talk was a success, but that may not be apparent from the video. Things went fine for the first 12 minutes, and then...things went less fine. Bugs in the slides. Questions I didn't answer. Material I didn't have time to cover. All of which may--should--make you wonder how I define "success."

As a general rule, I like to test material in front of live audiences before I put it in my books. Presenting technical material live is perhaps the best way to get feedback on it. Not only does it offer attendees an opportunity to ask questions and make comments (direct feedback), it gives me a chance to see people's reactions (indirect feedback). Even if an audience asks no questions and makes no comments, looking into their faces tells me if they're engaged or bored and if they're following what I'm saying or are confused. Plus, the simple act of explaining something gives me a chance to see how well it flows in practice. It's quite common for me to think to myself "this just isn't working the way I'd hoped..." while I'm speaking, and places where I think that identify parts of the presentation where I need to go back and make revisions.

From the presentation at the NWC++UG (including some conversations I had with attendees afterwards), I took away two primary lessons. First, the guideline I was presenting ("Avoid overloading on universal references")  is both valid and useful. That was reassuring. Second, the technical justification I give for this guideline needs a fair amount of work. In particular, I need to avoid getting side-tracked too much by the issues surrounding overloading on universal references and its interaction with compiler-generated special functions. Both lesson will help me produce a better book, and that's why I consider the talk a success.

At the same time, I was disappointed that there were bugs in my slides. I have pretty much a zero-tolerance mindset for errors in presentation materials (as well as books and articles and other forms of publication), because authors (including me) have essentially unlimited amounts of time to prepare the materials prior to making them public. (If there's insufficient time to prepare the materials properly, my feeling is that you shouldn't agree to present or publish them.) To be honest, I was also surprised that my materials had the errors that they did, because I hadn't skimped on prep time or QA work. I really thought they were ready to go. I was mistaken. In the future, I'll clearly have to find ways to do a better job.

Since giving the talk, I've corrected and revised the materials, and the corrected slide set is available here.

I hope you enjoy the talk, rocky parts notwithstanding.

Scott



Wednesday, July 10, 2013

C++11 Training Materials Updated--Now With C++14 Info!

For the seventh time since originally releasing them over three years ago, I've updated my annotated training materials for "The New C++". Until this update, "the new C++" referred to C++11, but with this revision, I'm including treatment of several features from draft C++14 that I believe will make it into the new new standard. As far as I know, this makes my training materials the first "book-like" publication that covers features in C++14.

In accord with my "free updates for life" policy, people who've purchased these materials are entitled to (and should recently have received notification about) the updated version.

The latest revision of the materials contains the usual mish-mash of bug-fixes and presentation improvements (the changelog, which is delivered along with the latest matereials, has details), and those alone had me planning a release this summer. But when the C++14 CD was adopted in April, I knew I had to find a way to shoehorn some C++14 material into the course. The result is 20 new pages of information, including overviews of the following C++14 features:
  • Polymorphic lambdas (i.e., auto parameters).
  • Generalized lambda captures (makes "move capture" possible).
  • Variadic and perfect-forwarding lambdas.
  • Generalized function return type deduction (i.e., auto return types).
  • Reader/writer locks (i.e., std::shared_mutex and std::shared_lock).
There's also a page summarizing other C++14 features, along with a slew of references for people who want to read more about the new goodies in C++14.

If you haven't done so already, I hope you'll consider purchasing a copy of these materials. As always, a free sample PDF of the first ~40 pages is available here. Don't expect too much C++14 information in that sample, because the first serious treatment of C++14 features begins on slide 90. That's not me being coy. It's just how things worked out, given the flow of topics in the course.

Scott

Sunday, July 7, 2013

When decltype meets auto

C++11 has three sets of type deduction rules:
  • Those used in template type deduction.
  • Those used in auto type deduction.
  • Those used by decltype.
The rules for auto type deduction are the same as the rules for template type deduction, except that given a braced initializer such as { 1, 2, 3, 4 }, auto will deduce a std::initializer list type (in the case of { 1, 2, 3, 4 }, it will be std::initializer_list<int>), while template type deduction will fail. (I have no idea why type deduction for auto and for templates is not identical. If you know, please tell me!) The rules for decltype are more complicated, because they don't just distinguish between lvalues and rvalues, they also distinguish between id-expressions (i.e., expressions consisting only of identifiers, e.g., variable or parameter names) and non-id-expressions. For details on all these rules, consult this article by Thomas Becker, this article by me, or this article by Herb Sutter (for auto) and this one by Andrew Koenig (for decltype).

But that's for C++11, which, among the C++-obsessed, is rapidly approaching yawnworthiness. Fortunately, C++14 is on the horizon, and one of the new features sure to stifle even the strongest of  yawns is the ability to declare types using decltype(auto). This feature leads to two questions, only the first of which is rhetorical:
  1. You can declare what?
  2. During type deduction for decltype(auto), which type deduction rules are to be followed: those for auto or those for decltype?  Or does decltype(auto) have its own set of type deduction rules?
The answer is that decltype(auto)uses the decltype type deduction rules. The reason is that the type deduced by auto for an initializing expression strips the ref-qualifiers (i.e., lvalue references and rvalue references) and top-level cv-qualifiers (i.e., consts and volatiles) from the expression, but decltype does not. As a result, if you want the ref- and cv-qualifier stripping behavior, you can just write auto. If you don't, C++14 gives you the option of writing decltype(auto).

For variable declarations, this saves you the trouble of typing the initializing expression twice,
decltype(longAndComplexInitializingExpression) var =
  longAndComplexInitializingExpression;                     // C++11

decltype(auto) var = longAndComplexInitializingExpression;  // C++14
For auto function return types (another new C++14 feature), it's even more convenient. Consider a function template, grab, that authenticates a user and, assuming authentication doesn't throw, returns the result of indexing into some container-like object. Bearing in mind that some standard containers return lvalue references from their operator[] operations (e.g., std::vector, std::deque), while others return proxy objects (e.g., std::vector<bool>), and I believe it would be valid to define a container such that invoking operator[] on an rvalue would yield an rvalue reference, the proper "generic" way to declare this function in C++11 would be (I think):
template<typename ContainerType, typename IndexType>                //C++11
auto grab(ContainerType&& container, IndexType&& index) -> 
  decltype(std::forward<ContainerType>(container)[std::forward<IndexType>(index)]);
{
  authenticateUser();
  return std::forward<ContainerType>(container)[std::forward<IndexType>(index)];
}

In C++14, I believe this can be simplified to the following, thanks to function return type deduction and decltype(auto):
template<typename ContainerType, typename IndexType>                // C++14
decltype(auto) grab(ContainerType&& container, IndexType&& index)
{
  authenticateUser();
  return std::forward<ContainerType>(container)[std::forward<IndexType>(index)];
}

Scott