4.6 KiB
Tutorial 2.1 Plan: Resource Management & The Rule of Zero
Objective: To master modern C++ resource management techniques, moving away from manual memory handling (new/delete) to the robust RAII (Resource Acquisition Is Initialization) idiom. This tutorial will demonstrate the "Rule of Zero" by refactoring a C++98-style class that requires manual memory management into a modern, safer equivalent using standard library containers and smart pointers.
1. Project Setup
To keep our tutorials organized, we will create a new directory for this lesson.
- Create a
tutorial-2directory: Inside theGeminiTutorialproject root. - Copy Configuration: Copy the
CMakeLists.txtand the.vscodedirectory fromtutorial-1into the newtutorial-2directory. This preserves our build and debug configurations. - Update
CMakeLists.txt: Modify theproject()name at the top oftutorial-2/CMakeLists.txtfromTutorial1toTutorial2.
2. The "Old Way": Manual Memory Management (The Rule of Three/Five)
First, we'll create a class that manually manages a dynamic array of doubles. This will highlight the complexity and risks of the C++98 approach.
File: tutorial-2/src/StockData_Old.h
#pragma once // Use modern include guard
#include <cstddef> // For size_t
class StockData_Old {
public:
// Constructor
StockData_Old(size_t size);
// Copy Constructor (Rule 1 of 3)
StockData_Old(const StockData_Old& other);
// Copy Assignment Operator (Rule 2 of 3)
StockData_Old& operator=(const StockData_Old& other);
// Destructor (Rule 3 of 3)
~StockData_Old();
// Public method to access data
double& at(size_t index);
private:
double* data_;
size_t size_;
};
We will also create the corresponding .cpp file to implement these special member functions, demonstrating the need for deep copies and manual cleanup.
3. The "Modern Way": Automatic Resource Management (The Rule of Zero)
Next, we will create a modern equivalent that leverages std::vector. This class will achieve the same functionality with significantly less code and greater safety.
File: tutorial-2/src/StockData_Modern.h
#pragma once
#include <vector>
class StockData_Modern {
public:
// Constructor
StockData_Modern(size_t size);
// No Copy Constructor, Copy Assignment, or Destructor needed!
// The compiler-generated versions work perfectly because `std::vector` handles itself.
// Public method to access data
double& at(size_t index);
private:
std::vector<double> data_;
};
This class adheres to the Rule of Zero, as it owns its resources through a standard library container and requires no custom resource management code.
4. Introducing Smart Pointers for Single Object Ownership
While containers are for sequences of objects, smart pointers manage the lifetime of a single dynamically allocated object.
std::unique_ptr: Represents exclusive ownership. The object is destroyed automatically when theunique_ptrgoes out of scope.std::shared_ptr: Represents shared ownership. The object is destroyed only when the lastshared_ptrpointing to it is destroyed.
We will create a simple Trade class and a main.cpp to demonstrate creating and managing Trade objects on the heap using both std::unique_ptr and std::shared_ptr.
5. Updating the Build System and Main Application
We will modify tutorial-2/CMakeLists.txt to include all our new source files (.cpp files for StockData_Old, StockData_Modern, and the new main.cpp).
The main.cpp will first use StockData_Old to illustrate its usage (and potential pitfalls), then use StockData_Modern to show the simplicity and safety of the modern approach, and finally demonstrate the usage of smart pointers.
6. Summary and Key Takeaways
This tutorial will provide hands-on experience with the core principles of modern C++ resource management:
- RAII: Let objects manage resources. Acquisition is in the constructor, release is in the destructor.
- Rule of Zero: By using standard library classes like
std::vector,std::string,std::unique_ptr, andstd::shared_ptrto handle resource ownership, your own classes often don't need any custom destructor, copy/move constructors, or assignment operators. - Expressing Ownership: Choose the right tool for the job:
std::vectorfor owning a dynamic array of elements.std::unique_ptrfor exclusive ownership of a single heap-allocated object.std::shared_ptrfor shared ownership of a single heap-allocated object.