RAII & SOLID — Core Design Principles
Prerequisites
1. RAII (Resource Acquisition Is Initialization)
RAII is a C++ design principle where resource allocation and deallocation are tied to object lifetime.
- Resource is acquired in constructor
- Resource is released in destructor
Main Key Concept
- resource tied to object lifetime
- constructor → acquire
- destructor → release
- core idiom in C++
Why It Matters
In C++, you manage resources manually:
- memory
- file handles
- mutex locks
❌ Without RAII
1
2
3
4
5
6
7
8
9
10
| void process()
{
FILE* f = fopen("file.txt", "r");
if (!f) return;
// ... do work
fclose(f); // might be skipped if error occurs
}
|
- early return
- exception
- missing cleanup
→ resource leak
✔ With RAII
1
2
3
4
5
6
7
8
| #include <fstream>
void process()
{
std::ifstream f("file.txt");
// automatically closed when f goes out of scope
}
|
Destructor guarantees cleanup ✔
RAII with Mutex
1
2
3
4
5
6
7
8
| std::mutex m;
void work()
{
std::lock_guard<std::mutex> lock(m);
// critical section
}
|
- lock acquired
- automatically released at scope end
Key Benefits
- exception safety
- no resource leaks
- cleaner code
- deterministic destruction
2. SOLID Principles
SOLID is a set of design principles that make software more maintainable, flexible, and scalable.
2-1. S — Single Responsibility Principle (SRP)
A class should have only one reason to change.
❌ Bad
1
2
3
4
5
6
| class Report
{
public:
void generate();
void saveToFile();
};
|
- generation + file I/O mixed
✔ Good
1
2
3
4
5
6
7
8
9
10
11
| class ReportGenerator
{
public:
void generate();
};
class ReportSaver
{
public:
void save();
};
|
2-2. O — Open/Closed Principle (OCP)
Open for extension, closed for modification.
❌ Bad
1
2
| if (type == "A") ...
else if (type == "B") ...
|
✔ Good
1
2
3
4
5
6
7
8
9
10
11
| class Shape
{
public:
virtual double area() = 0;
};
class Circle : public Shape
{
public:
double area() override { ... }
};
|
- add new types without modifying existing code
2-3. L — Liskov Substitution Principle (LSP)
Derived classes must be replaceable for their base class.
❌ Bad
1
2
3
4
5
6
7
8
9
10
11
| class Bird
{
public:
virtual void fly();
};
class Penguin : public Bird
{
public:
void fly() override { throw; }
};
|
✔ Good
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| class Bird
{
};
class FlyingBird : public Bird
{
public:
virtual void fly() = 0;
};
class Sparrow : public FlyingBird
{
public:
void fly() override { /* OK */ }
};
class Penguin : public Bird
{
};
|
2-4. I — Interface Segregation Principle (ISP)
Do not force clients to depend on unused interfaces.
❌ Bad
1
2
3
4
5
6
| class Machine
{
public:
virtual void print();
virtual void scan();
};
|
✔ Good
1
2
3
4
5
6
7
8
9
10
11
| class Printer
{
public:
virtual void print();
};
class Scanner
{
public:
virtual void scan();
};
|
2-5. D — Dependency Inversion Principle (DIP)
Depend on abstractions, not concrete implementations.
❌ Bad
1
2
3
4
5
6
| class Engine {};
class Car
{
Engine engine;
};
|
✔ Good
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
| class IEngine
{
public:
virtual void start() = 0;
};
class GasEngine : public IEngine
{
public:
void start() override
{
std::cout << "Gas engine start\n";
}
};
class ElectricEngine : public IEngine
{
public:
void start() override
{
std::cout << "Electric engine start\n";
}
};
class Car
{
IEngine* engine;
public:
Car(IEngine* e) : engine(e) {}
void start()
{
engine->start(); // virtual dispatch
}
};
|
1
2
3
4
5
6
7
8
9
10
11
| int main()
{
GasEngine gas;
ElectricEngine electric;
Car car1(&gas);
Car car2(&electric);
car1.start(); // Gas engine start
car2.start(); // Electric engine start
}
|
RAII & SOLID together in Practice
In real systems:
- RAII → safe resource handling
- SOLID → clean architecture
Example
1
2
3
4
5
6
7
| class FileProcessor
{
std::ifstream file; // RAII
public:
void process(); // SRP
};
|