Improving Stability with Modern C++, Part 1 — Getting Started

Ralph Kootker
FactSet
Published in
3 min readSep 30, 2021

C++ is a workhorse programming language across the financial industry. At FactSet, it has powered many of our products for almost 30 years. Because our code base predates C++ standardization, we have a lot of legacy code to support. However, we’ve recently completed a major compiler upgrade that enables our workstation developers to start using modern C++ for the first time. While C++ had a reputation for a steep learning curve, we’ve found the new features safer, easy to adopt, and more stable for our clients.

While the C++11 standard recently had its 10th birthday, there are still developers out there using modern C++ for the first time. With that in mind, we’ve prepared a series of short introductory posts on the features of C++11 and beyond. We’re sharing our journey with the wider C++ community in the hopes that others will find it as useful as we have.

Where Should I Begin?

There are two simple changes you can make right away. C++11 introduced the keywords nullptr and override. These new keywords are better than their legacy alternatives and are safe to use everywhere in your code. We’ll go over each one briefly below.

Replace NULL and 0 with nullptr

NULL is usually implemented as a macro defined as 0. While it's legal in C++ to compare a raw pointer with 0, it can cause issues because 0 is a valid value for multiple types. Consider the following code. Which overload will be called?

void foo(int) { std::cout << "Called int version"; }
void foo(bool) { std::cout << "Called bool version"; }
void foo(void*) { std::cout << "Called pointer version"; }
foo(NULL);

I don’t know, and it’s possible your compiler won’t either. It could select the int version as if you'd written foo(0), or it might fail to compile. However, foo(nullptr) is guaranteed to call the void* overload. nullptr has its own type, std::nullptr_t, that can implicitly convert to any raw pointer type. It's clearer, more correct, and safe to use anywhere you've used NULL previously:

foo(nullptr);
void* bar = nullptr;
if (baz != nullptr) { // alternatively, if (baz)
// ...
}

Tag overridden virtual functions with override

Have you ever had this bug?

struct Foo {
virtual void func(int a, std::string b, double c, float d);
};
struct Bar : Foo {
void func(int a, std::string b, float c, double d);
};
Foo* f = new Bar;
f->func(42, "baz", 3.2f, 7.9); // why wasn't Bar::func called?

The argument lists in both classes don’t match, thus Bar::func hides Foo::func instead of overriding it. C++11 added the override keyword to solve this problem. The compiler will issue an error if you mis-type the arguments, add an extra one, or if the const or reference qualifiers don't match.

struct Bar : Foo {
void func(int a, std::string b, float c, double d) override; // ERROR: argument list doesn't match base class
void func(int a, std::string b, double c, float d) override; // OK
};

As with nullptr, this is safe to use everywhere you have an overridden member function.

Side note for those with large legacy codebases

Tools such as clang-tidy can make both of these suggested changes for you. Consider using source-aware tooling instead of making these changes by hand.

Where can I learn more?

We’ve based much of our advice at FactSet on the ISO C++ Core Guidelines. See the guidelines for nullptr and override for more details.

What’s next?

Please comment below if you have any questions or suggestions for what topics we should cover next. Future posts we have planned include:

  • Range-based for loops
  • auto keyword
  • Memory management
  • Rule of Three
  • Move semantics
  • Perfect forwarding
  • Variadic templates

Acknowledgments

Special thanks to all that contributed to this blog post:

Author: Michael Kristofik
Managing Editor: Ralph Kootker
Reviewers: Phani Adusumilli, Jens Maurer, Tim Severijns

--

--

Ralph Kootker
FactSet
Writer for

I publish on behalf of others or myself. Please carefully look at the acknowledgements at the bottom of each article