Bài 17: Con trỏ nâng cao (Advanced Pointers)
📖 Giới thiệu
Con trỏ nâng cao (Advanced Pointers) bao gồm các khái niệm và kỹ thuật phức tạp hơn trong quản lý con trỏ và bộ nhớ. Đây là bước cuối cùng để thành thạo con trỏ trong C++.
Trong bài này chúng ta sẽ học:
- Function Pointers: Con trỏ trỏ đến hàm
- Pointer to Pointer: Con trỏ của con trỏ
- Smart Pointers: Con trỏ thông minh (C++11)
- Memory Management Patterns: Các mẫu quản lý bộ nhớ
- Advanced Applications: Ứng dụng thực tế
Những kỹ thuật này được sử dụng rộng rãi trong:
- System Programming: Lập trình hệ thống
- Game Development: Phát triển game
- Embedded Systems: Hệ thống nhúng
- High Performance Computing: Tính toán hiệu suất cao
🔧 Cú pháp
Function Pointers
cpp
// Khai báo function pointer
int (*funcPtr)(int, int); // Con trỏ đến hàm trả về int, nhận 2 int
void (*actionPtr)(); // Con trỏ đến hàm void không tham số
// Gán function pointer
int add(int a, int b) { return a + b; }
int multiply(int a, int b) { return a * b; }
funcPtr = add; // Gán địa chỉ hàm add
funcPtr = &multiply; // Hoặc dùng & (tùy chọn)
// Gọi qua function pointer
int result = funcPtr(5, 3); // Gọi hàm qua pointer
int result2 = (*funcPtr)(5, 3); // Cách khác (tùy chọn)Pointer to Pointer
cpp
int value = 42;
int* ptr = &value; // ptr trỏ đến value
int** ptrToPtr = &ptr; // ptrToPtr trỏ đến ptr
// Truy cập giá trị
cout << value; // 42
cout << *ptr; // 42
cout << **ptrToPtr; // 42
// Thay đổi giá trị qua pointer to pointer
**ptrToPtr = 100; // value = 100Smart Pointers (C++11)
cpp
#include <memory>
// unique_ptr: Sở hữu độc quyền
std::unique_ptr<int> uptr = std::make_unique<int>(42);
auto uptr2 = std::make_unique<int[]>(10); // Mảng
// shared_ptr: Sở hữu chung
std::shared_ptr<int> sptr = std::make_shared<int>(42);
std::shared_ptr<int> sptr2 = sptr; // Copy, tăng reference count
// weak_ptr: Quan sát không sở hữu
std::weak_ptr<int> wptr = sptr;🔬 Phân tích & Giải thích chi tiết
1. Function Pointers - Callback Programming
cpp
#include <iostream>
using namespace std;
// Các hàm toán học
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int multiply(int a, int b) { return a * b; }
int divide(int a, int b) { return b != 0 ? a / b : 0; }
// Hàm nhận function pointer làm callback
void calculate(int x, int y, int (*operation)(int, int), const char* name) {
int result = operation(x, y);
cout << x << " " << name << " " << y << " = " << result << endl;
}
// Mảng function pointers
int (*operations[])(int, int) = {add, subtract, multiply, divide};
const char* operationNames[] = {"+", "-", "*", "/"};
// Menu-driven calculator
void calculator() {
int x, y, choice;
cout << "=== CALCULATOR VỚI FUNCTION POINTERS ===" << endl;
cout << "Nhập hai số: ";
cin >> x >> y;
cout << "\nChọn phép toán:" << endl;
cout << "0. Cộng (+)" << endl;
cout << "1. Trừ (-)" << endl;
cout << "2. Nhân (*)" << endl;
cout << "3. Chia (/)" << endl;
cout << "Lựa chọn (0-3): ";
cin >> choice;
if (choice >= 0 && choice <= 3) {
calculate(x, y, operations[choice], operationNames[choice]);
} else {
cout << "Lựa chọn không hợp lệ!" << endl;
}
}
// Event system với callbacks
void onButtonClick() {
cout << "🖱️ Button được click!" << endl;
}
void onMouseMove() {
cout << "🐭 Mouse di chuyển!" << endl;
}
void onKeyPress() {
cout << "⌨️ Phím được nhấn!" << endl;
}
class EventSystem {
private:
void (*callbacks[10])(); // Mảng function pointers
int callbackCount;
public:
EventSystem() : callbackCount(0) {}
void registerCallback(void (*callback)()) {
if (callbackCount < 10) {
callbacks[callbackCount++] = callback;
}
}
void triggerEvents() {
cout << "\n🔥 Kích hoạt các events:" << endl;
for (int i = 0; i < callbackCount; i++) {
callbacks[i]();
}
}
};
int main() {
// Demo calculator
calculator();
// Demo event system
EventSystem eventSys;
eventSys.registerCallback(onButtonClick);
eventSys.registerCallback(onMouseMove);
eventSys.registerCallback(onKeyPress);
eventSys.triggerEvents();
return 0;
}2. Pointer to Pointer - Dynamic 2D Arrays
cpp
#include <iostream>
using namespace std;
// Cấp phát ma trận 2D động
int** allocateMatrix(int rows, int cols) {
// Cấp phát mảng con trỏ (hàng)
int** matrix = new int*[rows];
// Cấp phát từng hàng
for (int i = 0; i < rows; i++) {
matrix[i] = new int[cols];
}
return matrix;
}
// Giải phóng ma trận 2D
void deallocateMatrix(int** matrix, int rows) {
// Giải phóng từng hàng
for (int i = 0; i < rows; i++) {
delete[] matrix[i];
}
// Giải phóng mảng con trỏ
delete[] matrix;
}
// Nhập ma trận
void inputMatrix(int** matrix, int rows, int cols) {
cout << "Nhập ma trận " << rows << "x" << cols << ":" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << "matrix[" << i << "][" << j << "] = ";
cin >> matrix[i][j];
}
}
}
// In ma trận
void printMatrix(int** matrix, int rows, int cols) {
cout << "Ma trận:" << endl;
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
cout << matrix[i][j] << "\t";
}
cout << endl;
}
}
// Nhân hai ma trận
int** multiplyMatrices(int** mat1, int** mat2, int rows1, int cols1, int cols2) {
int** result = allocateMatrix(rows1, cols2);
for (int i = 0; i < rows1; i++) {
for (int j = 0; j < cols2; j++) {
result[i][j] = 0;
for (int k = 0; k < cols1; k++) {
result[i][j] += mat1[i][k] * mat2[k][j];
}
}
}
return result;
}
// Chuyển đổi con trỏ trong hàm
void swapPointers(int** ptr1, int** ptr2) {
int* temp = *ptr1;
*ptr1 = *ptr2;
*ptr2 = temp;
}
void demoPointerToPointer() {
cout << "=== DEMO POINTER TO POINTER ===" << endl;
// Ma trận động
int rows = 3, cols = 3;
int** matrix = allocateMatrix(rows, cols);
// Khởi tạo ma trận đơn vị
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
matrix[i][j] = (i == j) ? 1 : 0;
}
}
printMatrix(matrix, rows, cols);
deallocateMatrix(matrix, rows);
// Demo swap pointers
int a = 10, b = 20;
int* ptrA = &a;
int* ptrB = &b;
cout << "\nTrước swap: *ptrA = " << *ptrA << ", *ptrB = " << *ptrB << endl;
swapPointers(&ptrA, &ptrB);
cout << "Sau swap: *ptrA = " << *ptrA << ", *ptrB = " << *ptrB << endl;
}3. Smart Pointers - Modern C++ Memory Management
cpp
#include <iostream>
#include <memory>
#include <vector>
using namespace std;
class Resource {
private:
string name;
int id;
public:
Resource(const string& n, int i) : name(n), id(i) {
cout << "✅ Resource '" << name << "' được tạo (ID: " << id << ")" << endl;
}
~Resource() {
cout << "🗑️ Resource '" << name << "' được hủy (ID: " << id << ")" << endl;
}
void use() const {
cout << "🔧 Sử dụng resource '" << name << "' (ID: " << id << ")" << endl;
}
const string& getName() const { return name; }
int getId() const { return id; }
};
// Demo unique_ptr
void demoUniquePtr() {
cout << "\n=== UNIQUE_PTR DEMO ===" << endl;
{
// Tạo unique_ptr
auto resource1 = make_unique<Resource>("Unique Resource", 1);
resource1->use();
// Move ownership
auto resource2 = move(resource1);
// resource1 bây giờ là nullptr
if (resource1 == nullptr) {
cout << "resource1 đã bị move, giờ là nullptr" << endl;
}
resource2->use();
// Unique_ptr tự động delete khi ra khỏi scope
}
cout << "Scope kết thúc - unique_ptr tự động dọn dẹp" << endl;
}
// Demo shared_ptr
void demoSharedPtr() {
cout << "\n=== SHARED_PTR DEMO ===" << endl;
shared_ptr<Resource> resource1;
{
// Tạo shared_ptr
auto resource2 = make_shared<Resource>("Shared Resource", 2);
cout << "Reference count: " << resource2.use_count() << endl;
resource1 = resource2; // Copy, tăng reference count
cout << "Reference count sau copy: " << resource2.use_count() << endl;
resource1->use();
resource2->use();
// resource2 ra khỏi scope nhưng object vẫn tồn tại
}
cout << "Reference count sau khi resource2 out-of-scope: " << resource1.use_count() << endl;
resource1->use();
// Object sẽ bị delete khi resource1 cũng out-of-scope
}
// Demo weak_ptr - tránh circular reference
class Node {
public:
int data;
shared_ptr<Node> next;
weak_ptr<Node> parent; // Dùng weak_ptr để tránh cycle
Node(int val) : data(val) {
cout << "Node " << data << " được tạo" << endl;
}
~Node() {
cout << "Node " << data << " được hủy" << endl;
}
};
void demoWeakPtr() {
cout << "\n=== WEAK_PTR DEMO ===" << endl;
auto parent = make_shared<Node>(1);
auto child1 = make_shared<Node>(2);
auto child2 = make_shared<Node>(3);
// Thiết lập mối quan hệ
parent->next = child1;
child1->parent = parent; // weak_ptr, không tăng reference count
child1->next = child2;
child2->parent = child1;
cout << "Parent reference count: " << parent.use_count() << endl;
cout << "Child1 reference count: " << child1.use_count() << endl;
// Kiểm tra weak_ptr
if (auto parentPtr = child1->parent.lock()) {
cout << "Child1 có parent với data: " << parentPtr->data << endl;
}
}
// Custom deleter cho shared_ptr
void customDeleter(Resource* res) {
cout << "🔥 Custom deleter gọi cho " << res->getName() << endl;
delete res;
}
void demoCustomDeleter() {
cout << "\n=== CUSTOM DELETER DEMO ===" << endl;
{
shared_ptr<Resource> resource(new Resource("Custom Delete Resource", 4), customDeleter);
resource->use();
}
cout << "Custom deleter đã được gọi" << endl;
}
int main() {
demoUniquePtr();
demoSharedPtr();
demoWeakPtr();
demoCustomDeleter();
return 0;
}💻 Ví dụ minh họa
Hệ thống quản lý plugin động
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <map>
using namespace std;
// Interface cho plugin
class IPlugin {
public:
virtual ~IPlugin() = default;
virtual void execute() = 0;
virtual string getName() const = 0;
virtual string getVersion() const = 0;
};
// Plugin cụ thể
class MathPlugin : public IPlugin {
public:
void execute() override {
cout << "🧮 Math Plugin: 2 + 2 = " << (2 + 2) << endl;
}
string getName() const override { return "Math Plugin"; }
string getVersion() const override { return "1.0"; }
};
class TextPlugin : public IPlugin {
public:
void execute() override {
cout << "📝 Text Plugin: Hello from text processing!" << endl;
}
string getName() const override { return "Text Plugin"; }
string getVersion() const override { return "2.1"; }
};
class GraphicsPlugin : public IPlugin {
public:
void execute() override {
cout << "🎨 Graphics Plugin: Drawing a circle ⭕" << endl;
}
string getName() const override { return "Graphics Plugin"; }
string getVersion() const override { return "1.5"; }
};
// Plugin factory sử dụng function pointers
using PluginCreator = unique_ptr<IPlugin>(*)();
unique_ptr<IPlugin> createMathPlugin() {
return make_unique<MathPlugin>();
}
unique_ptr<IPlugin> createTextPlugin() {
return make_unique<TextPlugin>();
}
unique_ptr<IPlugin> createGraphicsPlugin() {
return make_unique<GraphicsPlugin>();
}
// Plugin Manager
class PluginManager {
private:
map<string, PluginCreator> pluginFactories;
vector<shared_ptr<IPlugin>> loadedPlugins;
public:
void registerPlugin(const string& name, PluginCreator creator) {
pluginFactories[name] = creator;
cout << "✅ Đăng ký plugin: " << name << endl;
}
bool loadPlugin(const string& name) {
auto it = pluginFactories.find(name);
if (it != pluginFactories.end()) {
auto plugin = it->second(); // Gọi function pointer
loadedPlugins.push_back(shared_ptr<IPlugin>(plugin.release()));
cout << "📦 Đã load plugin: " << name << endl;
return true;
}
cout << "❌ Không tìm thấy plugin: " << name << endl;
return false;
}
void listRegisteredPlugins() const {
cout << "\n📋 PLUGIN ĐÃ ĐĂNG KÝ:" << endl;
for (const auto& pair : pluginFactories) {
cout << " - " << pair.first << endl;
}
}
void listLoadedPlugins() const {
cout << "\n📦 PLUGIN ĐÃ LOAD:" << endl;
for (size_t i = 0; i < loadedPlugins.size(); i++) {
const auto& plugin = loadedPlugins[i];
cout << " " << (i + 1) << ". " << plugin->getName()
<< " v" << plugin->getVersion()
<< " (RefCount: " << plugin.use_count() << ")" << endl;
}
}
void executePlugin(int index) {
if (index > 0 && index <= loadedPlugins.size()) {
loadedPlugins[index - 1]->execute();
} else {
cout << "❌ Index plugin không hợp lệ!" << endl;
}
}
void executeAllPlugins() {
cout << "\n🚀 THỰC THI TẤT CẢ PLUGIN:" << endl;
for (const auto& plugin : loadedPlugins) {
plugin->execute();
}
}
shared_ptr<IPlugin> getPlugin(int index) {
if (index > 0 && index <= loadedPlugins.size()) {
return loadedPlugins[index - 1];
}
return nullptr;
}
void unloadPlugin(int index) {
if (index > 0 && index <= loadedPlugins.size()) {
string name = loadedPlugins[index - 1]->getName();
loadedPlugins.erase(loadedPlugins.begin() + index - 1);
cout << "🗑️ Đã unload plugin: " << name << endl;
} else {
cout << "❌ Index plugin không hợp lệ!" << endl;
}
}
int getLoadedCount() const { return loadedPlugins.size(); }
};
// Command pattern với function pointers
using Command = void(*)(PluginManager&);
void showMenu(PluginManager& pm) {
cout << "\n🔧 HỆ THỐNG QUẢN LÝ PLUGIN" << endl;
cout << "1. Liệt kê plugin đã đăng ký" << endl;
cout << "2. Load plugin" << endl;
cout << "3. Liệt kê plugin đã load" << endl;
cout << "4. Thực thi plugin" << endl;
cout << "5. Thực thi tất cả plugin" << endl;
cout << "6. Unload plugin" << endl;
cout << "7. Chia sẻ plugin" << endl;
cout << "0. Thoát" << endl;
cout << "Chọn chức năng (0-7): ";
}
void listRegistered(PluginManager& pm) {
pm.listRegisteredPlugins();
}
void loadPlugin(PluginManager& pm) {
string name;
cout << "Nhập tên plugin cần load: ";
cin >> name;
pm.loadPlugin(name);
}
void listLoaded(PluginManager& pm) {
pm.listLoadedPlugins();
}
void executePlugin(PluginManager& pm) {
pm.listLoadedPlugins();
if (pm.getLoadedCount() > 0) {
int index;
cout << "Nhập số thứ tự plugin: ";
cin >> index;
pm.executePlugin(index);
}
}
void executeAll(PluginManager& pm) {
pm.executeAllPlugins();
}
void unloadPlugin(PluginManager& pm) {
pm.listLoadedPlugins();
if (pm.getLoadedCount() > 0) {
int index;
cout << "Nhập số thứ tự plugin cần unload: ";
cin >> index;
pm.unloadPlugin(index);
}
}
void sharePlugin(PluginManager& pm) {
pm.listLoadedPlugins();
if (pm.getLoadedCount() > 0) {
int index;
cout << "Nhập số thứ tự plugin cần chia sẻ: ";
cin >> index;
auto plugin = pm.getPlugin(index);
if (plugin) {
cout << "📤 Chia sẻ plugin: " << plugin->getName() << endl;
cout << "RefCount trước chia sẻ: " << plugin.use_count() << endl;
// Giả lập chia sẻ
shared_ptr<IPlugin> sharedCopy = plugin;
cout << "RefCount sau chia sẻ: " << plugin.use_count() << endl;
sharedCopy->execute();
cout << "Plugin đã được chia sẻ thành công!" << endl;
}
}
}
int main() {
PluginManager manager;
// Đăng ký các plugin
manager.registerPlugin("math", createMathPlugin);
manager.registerPlugin("text", createTextPlugin);
manager.registerPlugin("graphics", createGraphicsPlugin);
// Command table
Command commands[] = {
nullptr, // 0 - exit
listRegistered, // 1
loadPlugin, // 2
listLoaded, // 3
executePlugin, // 4
executeAll, // 5
unloadPlugin, // 6
sharePlugin // 7
};
int choice;
do {
showMenu(manager);
cin >> choice;
if (choice > 0 && choice <= 7) {
commands[choice](manager);
} else if (choice != 0) {
cout << "❌ Lựa chọn không hợp lệ!" << endl;
}
} while (choice != 0);
cout << "👋 Cảm ơn bạn đã sử dụng hệ thống!" << endl;
return 0;
}🏋️ Thực hành
Bài tập 1: Callback-based Event System
cpp
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// Event data structure
struct Event {
string type;
void* data;
int timestamp;
};
// Event handler function pointer
using EventHandler = void(*)(const Event&);
// Event listeners
void onUserLogin(const Event& e) {
string* username = static_cast<string*>(e.data);
cout << "🔐 User logged in: " << *username << endl;
}
void onFileUploaded(const Event& e) {
string* filename = static_cast<string*>(e.data);
cout << "📁 File uploaded: " << *filename << endl;
}
void onMessageSent(const Event& e) {
string* message = static_cast<string*>(e.data);
cout << "💬 Message sent: " << *message << endl;
}
class EventSystem {
private:
vector<pair<string, EventHandler>> handlers;
public:
void subscribe(const string& eventType, EventHandler handler) {
handlers.push_back({eventType, handler});
}
void publish(const Event& event) {
for (const auto& pair : handlers) {
if (pair.first == event.type) {
pair.second(event);
}
}
}
};
int main() {
EventSystem eventSys;
// Subscribe to events
eventSys.subscribe("login", onUserLogin);
eventSys.subscribe("upload", onFileUploaded);
eventSys.subscribe("message", onMessageSent);
// Trigger events
string username = "john_doe";
Event loginEvent = {"login", &username, 12345};
eventSys.publish(loginEvent);
string filename = "report.pdf";
Event uploadEvent = {"upload", &filename, 12346};
eventSys.publish(uploadEvent);
return 0;
}Bài tập 2: Memory Pool với Smart Pointers
cpp
#include <iostream>
#include <memory>
#include <queue>
using namespace std;
template<typename T>
class MemoryPool {
private:
queue<unique_ptr<T>> pool;
size_t poolSize;
public:
MemoryPool(size_t size) : poolSize(size) {
for (size_t i = 0; i < size; i++) {
pool.push(make_unique<T>());
}
}
shared_ptr<T> acquire() {
if (pool.empty()) {
return make_shared<T>();
}
auto obj = shared_ptr<T>(pool.front().release());
pool.pop();
return obj;
}
void release(T* obj) {
if (pool.size() < poolSize) {
pool.push(unique_ptr<T>(obj));
} else {
delete obj;
}
}
size_t available() const { return pool.size(); }
};
struct GameObject {
int id;
string name;
GameObject() : id(0), name("Default") {
cout << "GameObject created" << endl;
}
~GameObject() {
cout << "GameObject destroyed" << endl;
}
};
int main() {
MemoryPool<GameObject> pool(3);
cout << "Available objects: " << pool.available() << endl;
auto obj1 = pool.acquire();
auto obj2 = pool.acquire();
cout << "Available objects: " << pool.available() << endl;
return 0;
}📋 Tóm tắt
Kiến thức đã học:
Function Pointers:
- Trỏ đến địa chỉ hàm
- Callback programming
- Event systems
- Plugin architectures
Pointer to Pointer:
- Con trỏ cấp 2
- Dynamic 2D arrays
- Parameter passing
- Linked data structures
Smart Pointers:
unique_ptr: Sở hữu độc quyềnshared_ptr: Sở hữu chung, reference countingweak_ptr: Quan sát, tránh circular reference- Custom deleters
Advanced Patterns:
- RAII (Resource Acquisition Is Initialization)
- Plugin systems
- Memory pools
- Command patterns
Best Practices:
- Prefer smart pointers over raw pointers
- Use unique_ptr by default, shared_ptr khi cần
- Always check for nullptr before dereferencing
- Avoid circular references với weak_ptr
- Use RAII pattern for resource management
Modern C++ Recommendations:
make_unique/make_sharedthay vìnewautođể giảm code verbosity- Range-based for loops
- Lambda functions thay vì function pointers (khi phù hợp)
"Advanced pointers giống như công cụ của thầy phù thủy - mạnh mẽ nhưng cần khéo léo sử dụng!"
Chúc mừng! Bạn đã hoàn thành khóa học C++ từ cơ bản đến nâng cao. Hãy tiếp tục thực hành và khám phá Object-Oriented Programming, STL, và Modern C++ để trở thành một C++ developer chuyên nghiệp!