首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ 簡單記憶體區塊自動管理類別實作:RAII 原則與動態增長緩衝區

     編輯:關於C++

設計目標

實作一個 Mem 類別,封裝動態記憶體管理:

  • 建構時可選預配大小
  • 自動擴容 (保留舊資料、新增區域歸零)
  • 提供指標存取、大小查詢
  • 解構自動釋放 (RAII)
  • 展示正確/錯誤的預設參數用法

完整 Mem 類別實作


#ifndef MEM_H
#define MEM_H

#include   // memcpy, memset

typedef unsigned char byte;

class Mem {
    byte* mem_;
    int size_;
    
    void ensureMinSize(int minSize) {
        if (size_ < minSize) {
            byte* newMem = new byte[minSize];
            std::memset(newMem + size_, 0, minSize - size_);  // 新增區域歸零
            std::memcpy(newMem, mem_, size_);                 // 複製舊資料
            delete[] mem_;
            mem_ = newMem;
            size_ = minSize;
        }
    }

public:
    Mem() : mem_(nullptr), size_(0) {}
    explicit Mem(int sz) : mem_(nullptr), size_(0) { ensureMinSize(sz); }
    ~Mem() { delete[] mem_; }
    
    // 禁止複製 (淺拷貝風險),C++11 刪除
    Mem(const Mem&) = delete;
    Mem& operator=(const Mem&) = delete;
    
    // 移動語意 (C++11)
    Mem(Mem&& other) noexcept : mem_(other.mem_), size_(other.size_) {
        other.mem_ = nullptr; other.size_ = 0;
    }
    Mem& operator=(Mem&& other) noexcept {
        if (this != &other) {
            delete[] mem_;
            mem_ = other.mem_; size_ = other.size_;
            other.mem_ = nullptr; other.size_ = 0;
        }
        return *this;
    }

    int msize() const { return size_; }
    
    // 重載:無參數回傳當前指標,有參數確保最小大小並回傳
    byte* pointer() { return mem_; }
    byte* pointer(int minSize) { ensureMinSize(minSize); return mem_; }
};

#endif

應用範例:動態字串類別 MyString


#include "Mem.h"
#include 
#include 

class MyString {
    Mem* buf_;
public:
    MyString() : buf_(nullptr) {}
    explicit MyString(const char* str) {
        buf_ = new Mem(strlen(str) + 1);
        std::strcpy(reinterpret_cast(buf_->pointer()), str);
    }
    ~MyString() { delete buf_; }
    
    void concat(const char* str) {
        if (!buf_) buf_ = new Mem();
        int oldLen = buf_->msize() ? strlen(reinterpret_cast(buf_->pointer())) : 0;
        int addLen = strlen(str);
        // 關鍵:pointer(新大小) 觸發自動擴容
        std::strcat(reinterpret_cast(buf_->pointer(buf_->msize() + addLen + 1)), str);
    }
    
    void print(std::ostream& os) const {
        if (buf_) os << reinterpret_cast(buf_->pointer()) << std::endl;
    }
};

預設參數陷阱與正確重載對比

❌ 錯誤示範:用預設參數決定執行路徑


// 錯誤:呼叫端無法明確表達意圖,內部邏輯混雜
void Mystring::Mystring(char *str) {
    if (!*str) { buf_ = 0; return; }  // 空字串特判混在建構函式
    buf_ = new Mem(strlen(str)+1);
    strcpy((char*)buf_->pointer(), str);
}

✅ 正確示範:重載函式分離語意


// 正確:兩個建構函式,語意清晰
MyString() : buf_(nullptr) {}  // 空字串
explicit MyString(const char* str) {  // 非空字串
    buf_ = new Mem(strlen(str)+1);
    strcpy(reinterpret_cast(buf_->pointer()), str);
}

原則:不要用預設參數作為「分支旗標」決定執行邏輯。應拆分為多個重載函式,各司其職,編譯器靜態綁定,零運行開銷、意圖明確。

測試主程式


int main() {
    MyString s("Hello");
    s.print(std::cout);  // Hello
    s.concat(", World!");
    s.print(std::cout);  // Hello, World!
    return 0;
}

現代 C++ 改進方向

改進點方案
手動 new/delete改用 std::unique_ptr 或 std::vector
字串操作直接用 std::string (SSO 小字串優化、完美轉移)
緩衝區增長策略指數增長 (×1.5 或 ×2) 減少重配次數,而非精確增長
異常安全new 失敗拋 bad_alloc,RAII 保證不洩漏

教學價值:此範例展示 RAII (資源獲取即初始化) 核心模式:建構函式獲取資源、解構函式釋放資源、拷貝/移動語意正確處理所有權。這是現代 C++ 資源管理的基石,理解它才能真正掌握智慧指標、容器、鎖等高階設施的內在邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved