Refactoring is defined as the process of changing a software system in such a way that it does not alter the external behavior of the code yet improves its internal structure.
We can identify three approaches managers typically take to code refactoring:
- Iterative refactoring: your application can’t be developed perfectly in the first iteration, even if the team has the best architects, designers, and developers. A practical way to refactor without investing a lot of money or wasting time is to integrate refactoring into the development process and perform it after each iteration.
- Refactoring when necessary: after the application is deployed, some bugs are reported; if resolving them takes a lot of time, or some client requirements are very difficult to develop and integrate into the existing system, refactoring can be a good solution to improve the quality of the code base. But in this case it can be very risky, and care must be taken to avoid regressions in the existing code.
- No refactoring: sometimes, even if there are many problems in the existing application, refactoring is never undertaken because management does not want to invest in the process, and the support team has to deal with the stress generated by all the bugs and feedback.
If your team regularly refactors its C++ projects and has chosen to use some new C++11/C++14 features, it is useful to see how other well-known C++ projects have refactored their code to adopt the new standards.
The Chrome browser is a good project to examine: they refactor their code base regularly, and as soon as the new standards were approved and supported by compilers, the Chrome development team chose to move forward with these new standards.
The Chrome browser is a mature C++ project, and it is very interesting to explore how its code is implemented and designed. Indeed, Chrome is used by millions of users, which requires its development team to produce efficient code.
If you decide to refactor your C++ code base to use the new standards’ features, it is worth taking a look at this interesting Google document, which lists the allowed C++11/C++14 features and also the banned ones.
The most relevant part of this document is the list of banned features and the reasons they are banned. It is well worth reviewing this list to see whether it also applies to your projects.
Here are the banned C++11/C++14 features from the document:
C++11 Banned Features
| Feature or Library | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Inline Namespaces | inline namespace foo { ... } |
Allows better versioning of namespaces | Inline namespaces | Banned in the Google Style Guide. Unclear how it will work with components. |
long long Type |
long long var = value; |
An integer of at least 64 bits | Fundamental types | Use a stdint.h type if you need a 64bit number. Discussion thread |
| Ref-qualified Member Functions | class T {
void f() & {}
void f() && {}
};
t.f(); // first
T().f(); // second
std::move(t).f(); // second |
Allows class member functions to only bind to |this| as an rvalue or lvalue. | const-, volatile-, and ref-qualified member functions | Banned in the Google Style Guide. May only be used in Chromium with explicit approval from styleguide/c++/OWNERS. Discussion Thread |
| User-Defined Literals | type var = literal_value_type |
Allows user-defined literal expressions | User-defined literals | Banned in the Google Style Guide. |
| thread_local storage class | thread_local int foo = 1; |
Puts variables into thread local storage. | Storage duration | Some surprising effects on Mac (discussion, fork). Use SequenceLocalStorageSlot for sequence support, and ThreadLocal/ThreadLocalStorageotherwise. |
C++14 Banned Features
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Function return type deduction | auto f() { return 42; }
decltype(auto) g() { return 42; } |
Allows the return type of a function to be automatically deduced from its return statements, according to either template or decltype rules. |
Return type deduction | Temporarily banned since it can cause infinite loops in clang. We expect to allow this once that bug is fixed. Usage should be rare, primarily for abstract template code. Discussion thread |
| Generic lambdas | [](const auto& x) { ... } |
Allows lambda argument types to be deduced using auto (according to the rules that apply to templates). |
lambda expressions | Temporarily banned since it can cause infinite loops in clang. We expect to allow this once that bug is fixed. Discussion thread |
C++11 Banned Library Features
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
| Aligned storage | std::aligned_storage<10, 128> |
Uninitialized storage for objects requiring specific alignment. | std::aligned_storage | MSVC 2017's implementation does not align on boundaries greater than sizeof(double) = 8 bytes. Use alignas(128) char foo[10]; instead. Patch where this was discovered. |
| Bind Operations | std::bind(function, args, ...) |
Declares a function object bound to certain arguments | std::bind | Use base::Bind instead. Compared to std::bind, base::Bind helps prevent lifetime issues by preventing binding of capturing lambdas and by forcing callers to declare raw pointers as Unretained. Discussion thread |
| C Floating-Point Environment | <cfenv>, <fenv.h> |
Provides floating point status flags and control modes for C-compatible code | Standard library header <cfenv> | Banned by the Google Style Guide due to concerns about compiler support. |
| Date and time utilities | <chrono> |
A standard date and time library | Date and time utilities | Overlaps with Time APIs in base/. Keep using the base/ classes. |
| Exceptions | <exception> |
Enhancements to exception throwing and handling | Standard library header <exception> | Exceptions are banned by the Google Style Guide and disabled in Chromium compiles. Note that the noexcept specifier is explicitly allowed above. Discussion thread |
| Function Objects | std::function |
Wraps a standard polymorphic function | std::function | Use base::Callback instead. Compared to std::function, base::Callback directly supports Chromium's refcounting classes and weak pointers and deals with additional thread safety concerns. Discussion thread |
| Ratio Template Class | std::ratio<numerator, denominator> |
Provides compile-time rational numbers | std::ratio | Banned by the Google Style Guide due to concerns that this is tied to a more template-heavy interface style. |
| Regular Expressions | <regex> |
A standard regular expressions library | Regular expressions library | Overlaps with many regular expression libraries in Chromium. When in doubt, use re2. |
| Shared Pointers | std::shared_ptr |
Allows shared ownership of a pointer through reference counts | std::shared_ptr | Needs a lot more evaluation for Chromium, and there isn't enough of a push for this feature. Google Style Guide. Discussion Thread |
| Thread Library | <thread> and related headers, including
<future>, <mutex>, <condition_variable> |
Provides a standard multithreading library using std::thread and associates |
Thread support library | Overlaps with many classes in base/. Keep using the base/ classes for now. base::Thread is tightly coupled to MessageLoop which would make it hard to replace. We should investigate using standard mutexes, or unique_lock, etc. to replace our locking/synchronization classes. |
C++14 Banned Library Features
This section lists C++14 library features that are not allowed in the Chromium codebase.
| Feature | Snippet | Description | Documentation Link | Notes and Discussion Thread |
|---|---|---|---|---|
std::chrono literals |
using namespace std::chrono_literals;
auto timeout = 30s; |
Allows std::chrono types to be more easily constructed. |
std::literals::chrono_literals::operator""s | Banned because <chrono> is banned. |
Conclusion
Exploring the source code of well-known open-source projects to understand their design and implementation choices may be one of the best ways to learn how to write efficient code. Well-known C++ projects are generally developed by C++ experts who strive to apply best practices.
To sum up, take a look at the Chromium source code — it is well worth your time.
