Subtle Bug with std::min/max Function Templates

Suppose you have a function f that returns a double, and you want to store in a variable the value of this function, if this a positive number, or zero if the return value is negative. This line of C++ code tries to do that:

double x = std::max(0, f(/* something */));

Unfortunately, this apparently innocent code won’t compile!

The error message produced by VS2015’s MSVC compiler is not very clear, as often with C++ code involving templates.

So, what’s the problem with that code?

The problem is that the std::max function template is declared something like this:

template <typename T> 
const T& max(const T& a, const T& b)

If you look at the initial code invoking std::max, the first argument is of type int; the second argument is of type double (i.e. the return type of f).

Now, if you look at the declaration of std::max, you’ll see that both parameters are expected to be of the same type T. So, the C++ compiler complains as it’s unable to deduce the type of T in the code calling std::max: should T be int or double?

This ambiguity triggers a compile-time error.

To fix this error, you can use the double literal 0.0 instead of 0.

And, what if instead of 0 there’s a variable of type int?

Well, in this case you can either static_cast that variable to double:

double x = std::max(static_cast<double>(n), f(/* something */));

or, as an alternative, you can explicitly specify the double template type for std::max:

double x = std::max<double>(n, f(/* something */));

Learning Modern C++ from Scratch

C++ is a language having a reputation of being hard to learn.

In this C++ course of mine published by Pluralsight, I did my best to prove the opposite: C++ can be learned in a simple, interesting, and fun way!

I used a variety of engaging visuals, metaphors and example demo code to try to teach modern, clear, good C++ from scratch, from the beginning, without any previous programming knowledge.

And, even if you already know C++, you may have fun watching this course as well.

Note: The table of contents and a brief course overview are freely available in the course page.

Sample slide: Iterating through vector elements
Sample slide: Iterating through std::vector’s elements

Here’s some of what my reviewers wrote about this course:

You sound really passionate about this technology.  It comes across in the narration and it’s quite infectious.

You’re a very talented teacher, offering lots of examples, analogies and stories that make the concepts easy to grasp.  The visuals are also really helpful for understanding the concepts.

Overall, I really enjoyed this module.  The content is logically structured, you do a great job explaining the concepts, supported by engaging visuals.  There’s also a nice mix of theory and demos.  You clearly understand your beginner audience, the knowledge they currently have, and how to lead them to a deeper understanding of this technology.  Bravo!

The demo showing the bug with implementing the swap function was excellent. It immediately reinforced your earlier lesson on the scope of local variables.

Fantastic use of Camtasia callouts in the demos.

Sample slide: Introducing the std::string class
Sample slide: Introducing the std::string class

I’d like to sincerely thank Mike Woodring of Pluralsight for approving this course idea, my fantastic editor Beth Gerard-Hess for her continuous encouragement and support during this course production (working with Beth is an absolute pleasure), Stephan T. Lavavej for interesting email conversations that provided good food for thought, all my reviewers (both peer and QA) for their quality course feedback, and all the Pluralsight persons who worked on this course.

This C++ course has been a work of love for me, I put my heart into it: I hope you will enjoy the result!

 

The Small String Optimization

How do “Connie” and “meow” differ from “The Commodore 64 is a great computer”?

(Don’t get me wrong: They are all great strings! 🙂 )

In several implementations, including the Visual C++’s one, the STL string classes are empowered by an interesting optimization: The Small String Optimization (SSO).

What does that mean?

Well, it basically means that small strings get a special treatment. In other words, there’s a difference in how strings like “Connie”, “meow” or “The Commodore 64 is a great computer” are allocated and stored by std::string.

In general, a typical string class allocates the storage for the string’s text dynamically from the heap, using new[]. In Visual Studio’s C/C++ run-time implementation on Windows, new[] calls malloc, which calls HeapAlloc (…which may probably call VirtualAlloc). The bottom line is that dynamically-allocating memory with new[] is a non-trivial task, that does have an overhead, and implies a trip down the Windows memory manager.

So, the std::string class says: “OK, for small strings, instead of taking a trip down the new[]-malloc-HeapAlloc-etc. “memory lane” 🙂 , let’s do something much faster and cooler! I, the std::string class, will reserve a small chunk of memory, a “small buffer” embedded inside std::string objects, and when strings are small enough, they will be kept (deep-copied) in that buffer, without triggering dynamic memory allocations.”

That’s a big saving! For example, for something like:

std::string s{"Connie"};

there’s no memory allocated on the heap! “Connie” is just stack-allocated. No new[], no malloc, no HeapAlloc, no trip down the Windows memory manager.

That’s kind of the equivalent of this C-ish code:

char buffer[ /* some short length */ ];
strcpy_s(buffer, "Connie");

No new[], no HeapAlloc, no virtual memory manager overhead! It’s just a simple snappy stack allocation, followed by a string copy.

But there’s more! In fact, having the string’s text embedded inside the std::string object offers great locality, better than chasing pointers to scattered memory blocks allocated on the heap. This is also very good when strings are stored in a std::vector, as small strings are basically stored in contiguous memory locations, and modern CPUs love blasting contiguous data in memory!

Optimizations similar to the SSO can be applied also to other data structures, for example: to vectors. This year’s CppCon had an interesting session discussing that: “High Performance Code 201: Hybrid Data Structures”.

I’ve prepared some C++ code implementing a simple benchmark to measure the effects of SSO. The results I got for 200,000-small-string vectors clearly show a significant advantage of STL strings for small strings. For example: in 64-bit build on an Intel i7 CPU @3.40GHz: vector::push_back time for ATL (CStringW) is 29 ms, while for STL (wstring) it’s just 14 ms: one half! Moreover, sorting times are 135 ms for ATL vs. 77 ms for the STL: again, a big win for the SSO implemented in the STL!

 

Member Functions with Generic Parameters

Someone wanted to write a C++ class member function to operate on a generic container.

His thought process was: “Since in C++14 we can use auto with lambda parameters, why not using it also for class method parameters?

class MyClass {
  ...

  // DOESN’T work in C++14!!
  void DoSomething(auto& container) {
    ...

Unfortunately, this code doesn’t compile. In fact, in C++14 “auto” is not a valid parameter type for member functions.

Visual Studio 2015 emits the following error:

error C3533: a parameter cannot have a type that contains ‘auto’

To fix that code, we can use templates. The member function with an “auto” parameter can be written as a member function template:

class MyClass {
  ...

  //
  // Simulate:
  //
  //   void DoSomething(auto& container)
  //
  // using templates.
  //
  template <typename Container>
  void DoSomething(Container& container) {
    ...

Beginner’s Bug: What’s Wrong with Brace-Init and std::vector?

Question: I have some old C++ code that creates a std::vector containing two NUL wchar_ts:

std::vector<wchar_t> v(2, L'\0');

This code works just fine. I tried to modernize it, using C++11’s brace-initialization syntax:

// Braces {} used instead of parentheses () 
// to initialize v
std::vector<wchar_t> v{2, L'\0'};

However, now I have a bug in my new C++ code! In fact, the brace-initialized vector now contains a wchar_t having code 2, and a NUL. But I wanted two NULs! What’s wrong with my code?

Answer: The problem is that the new C++11 brace initialization syntax (more precisely: direct-list-initialization) in this vector case stomps (prevails) on the initialize-with-N-copies-of-X constructor overload that was used in the original code. So, the vector gets initialized with the content of the braced initialization list: {2, L’\0’}, i.e. a wchar_t having code 2, and a NUL.

I’m sorry: to get the expected original behavior you have to stick with the classical C++98 parentheses initialization syntax.

 

A Beginner’s Bug with C++11 Range-For Loops

This is an interesting bug that may affect C++11 novices. I’m proposing it in a Q&A form below.

Q. I have this old C++ code that uses a for loop to convert an ASCII string to upper-case:

std::string s = "Connie";

// Convert string to upper-case
for (size_t i = 0; i < s.length(); i++) {
  s[i] = std::toupper(s[i]);
}

std::cout << s << '\n';

This code works just fine and prints “CONNIE” as expected.

I tried to modernize this code, using C++11’s range-for loops. I rewrote the previous loop like this:

for (auto ch : s) {
  ch = std::toupper(ch);
}

Unfortunately, it doesn’t work: the output is still the original “Connie” string, not the expected upper-case version.

What’s wrong with that code?

A. The problem is in this line:

for (auto ch : s) {

Using this “auto ch” syntax, at each iteration step, the ch variable contains a copy of the original char in the string.

So, in the body of the range-for loop:

  ch = std::toupper(ch);

at every iteration step you are just converting to upper-case a temporary copy of the original string characters, not the original characters themselves!

What you really want to is iterating through the original string characters in place, instead of operating on temporary copies.

The “auto&” syntax (note the “&”) is what will make it work:

// Iterate through the string characters *in place*.
// NOTE the "&"!!
for (auto& ch : s) {
  ch = std::toupper(ch);
}

I wrote some simple practical advice for range-for loops in this blog post. For more details on using range-for loops, you may want to read this Q&A on StackOverflow.

 

A Simple STL vs. ATL String Performance Test – And the Winner Is… STL!

EDIT: New Performance Test available here.

 

In addition to the previous GotW#45 tests executed for the ATL’s and STL’s strings, I wanted to try my own tests. So I developed some simple C++ code that builds a std::vector of strings, and then sorts that vector. This test is executed for both ATL’s CStringW and STL’s wstring. Both the insertion times and sorting times are recorded.

You can check it out on GitHub.

The code was compiled with VS2015, and executed on an Intel i7 workstation running Windows 10 64-bit.

As you can see from the following screenshots, the STL string class always wins (faster execution times). In particular, when the test is executed for tiny strings, the STL’s small string optimization (SSO) is a clear winner over ATL’s CString.

Testing ATL vs. STL String Performance
Testing ATL vs. STL String Performance
Testing ATL vs. STL String Performance (SSO)
Testing ATL vs. STL String Performance (SSO)

I recall I did some similar measurements with older VC++ compiler versions (probably VS2008) and ATL’s CString was a winner back then. C++11’s move semantics and other improvements in the MSVC compiler and in the STL implementation made an important difference here. Kudos to the Visual C++ Team’s compiler and STL library guys for the improvements!