110 lines
4.6 KiB
Markdown
110 lines
4.6 KiB
Markdown
# 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.
|
|
|
|
1. **Create a `tutorial-2` directory:** Inside the `GeminiTutorial` project root.
|
|
2. **Copy Configuration:** Copy the `CMakeLists.txt` and the `.vscode` directory from `tutorial-1` into the new `tutorial-2` directory. This preserves our build and debug configurations.
|
|
3. **Update `CMakeLists.txt`:** Modify the `project()` name at the top of `tutorial-2/CMakeLists.txt` from `Tutorial1` to `Tutorial2`.
|
|
|
|
---
|
|
|
|
## 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`
|
|
```cpp
|
|
#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`
|
|
```cpp
|
|
#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.
|
|
|
|
1. **`std::unique_ptr`:** Represents exclusive ownership. The object is destroyed automatically when the `unique_ptr` goes out of scope.
|
|
2. **`std::shared_ptr`:** Represents shared ownership. The object is destroyed only when the last `shared_ptr` pointing 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`, and `std::shared_ptr` to 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::vector` for owning a dynamic array of elements.
|
|
* `std::unique_ptr` for exclusive ownership of a single heap-allocated object.
|
|
* `std::shared_ptr` for shared ownership of a single heap-allocated object.
|