Skip to main content

C++ Language-Specific Rules - Part 4: Modern C++

Based on Scott Meyers' Effective Modern C++ and C++11/14/17/20 features

Part of a multi-file C++ rules series:

  • lang-cpp-basics.md - Formatting, language basics, constructors, RAII
  • lang-cpp-design.md - Design, declarations, and implementations
  • lang-cpp-advanced.md - OOP, templates, and advanced topics
  • lang-cpp-modern.md (this file) - Modern C++ (C++11/14/17/20)
  • lang-cpp-guidelines.md - C++ Core Guidelines
  • lang-cpp-reference.md - Quick reference checklist

Modern C++ (C++11/14/17/20)

Smart Pointers Best Practices

std::unique_ptr (Preferred):

  • Zero overhead compared to raw pointers
  • Exclusive ownership
  • Movable but not copyable
  • Can have custom deleters
auto pw = std::make_unique<Widget>();
std::unique_ptr<Widget, decltype(&deleter)> pw(new Widget, deleter);
```text

**std::shared_ptr**:
- Reference counted
- Thread-safe reference counting
- Slightly heavier than unique_ptr
- Can have custom deleters
```cpp
auto pw = std::make_shared<Widget>(); // More efficient than new
```text

**std::weak_ptr**:
- Breaks cycles in shared_ptr graphs
- Doesn't affect reference count
- Must check if resource still exists before use
```cpp
std::weak_ptr<Widget> wpw = spw;
if (auto spt = wpw.lock()) { // Check if still alive
// Use spt
}
```text

### Rule of Zero/Three/Five

**Rule of Zero** (Preferred):
- Don't define any special member functions
- Let compiler generate them
- Use std::unique_ptr, std::vector, etc.
```cpp
class Widget {
std::string name;
std::vector<int> data;
std::unique_ptr<Impl> pImpl;
// Compiler-generated special members work perfectly!
};
```text

**Rule of Three** (Pre-C++11):
- If you define one of: destructor, copy constructor, copy assignment
- You probably need to define all three

**Rule of Five** (C++11+):
- If you define any special member function, define or delete all five:
- Destructor
- Copy constructor
- Copy assignment operator
- Move constructor
- Move assignment operator
```cpp
class Resource {
public:
~Resource(); // Destructor
Resource(const Resource&); // Copy constructor
Resource& operator=(const Resource&); // Copy assignment
Resource(Resource&&) noexcept; // Move constructor
Resource& operator=(Resource&&) noexcept; // Move assignment
};
```text

### Move Semantics

**When to provide move operations:**
- When copying is expensive
- When managing resources
- For containers and large objects

```cpp
class Buffer {
public:
// Move constructor
Buffer(Buffer&& other) noexcept
: data(std::exchange(other.data, nullptr)),
size(std::exchange(other.size, 0))
{ }

// Move assignment
Buffer& operator=(Buffer&& other) noexcept {
if (this != &other) {
delete[] data;
data = std::exchange(other.data, nullptr);
size = std::exchange(other.size, 0);
}
return *this;
}

private:
char* data;
size_t size;
};
```text

**noexcept** is important for move operations:
- Enables optimizations (like std::vector growth)
- Should be noexcept whenever possible

## References and Sources

**Books:**
- [Effective C++: 55 Specific Ways to Improve Your Programs and Designs](https://www.amazon.com/Effective-Specific-Improve-Programs-Designs/dp/0321334876) by Scott Meyers
- [Effective Modern C++: 42 Specific Ways to Improve Your Use of C++11 and C++14](https://www.amazon.com/Effective-Modern-Specific-Ways-Improve/dp/1491903996) by Scott Meyers
- [More Effective C++: 35 New Ways to Improve Your Programs and Designs](https://www.amazon.com/More-Effective-Improve-Programs-Designs/dp/020163371X) by Scott Meyers

**Online Resources:**
- [C++ Core Guidelines](https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines) - ISO C++ community standards
- [Effective C++ Items Summary](https://gist.github.com/asambol/fa234c747ba4a677dee7b2ddaa64778d) - Community reference
- [C++ Core Guidelines: Resource Management](https://www.modernescpp.com/index.php/c-core-guidelines-rules-to-resource-management/)
- [C++ Core Guidelines: Smart Pointers](https://www.modernescpp.com/index.php/c-core-guidelines-rules-to-smart-pointers/)