1. 程式人生 > >【C++】記憶體對齊和簡單的記憶體管理

【C++】記憶體對齊和簡單的記憶體管理

記憶體管理

自己申請一個記憶體塊,用來存放構造的資料,使用placement new在記憶體上構造資料。
示例:

//待操作的資料
struct Data 
{
    Data(int _a, char _b, double _c) :a(_a), b(_b), c(_c) {}
    int    a;
    char   b;
    double c;
};

class Block
{
public:
    template<class T, class... Args>
    T* getPtr(Args&&...args)
    {
        //placement new
T* ptr = new(block + pos) T(std::forward<Args>(args)...); int size = sizeof(T); cout << "Request block :" << typeid(T).name() << " size:" << size << " pos:" << pos << endl; pos += size; return ptr; } void
print() { for (int i = 0; i < 5; ++i) { for (int j = 0; j < 16; ++j) { printf("%x|", block[i * 10 + j]); } cout << endl; } } //直接從記憶體取出物件 template<class T> T* getPtr(int index) { int
size = sizeof(T); char* p = block + size * index; return reinterpret_cast<T*>(p); } private: int pos = 0; char block[90] = {0}; }; int main() { Block block; block.print(); //申請一個Data資料,記憶體存放在block中 Data* ptr1 = block.getPtr<Data>(1,'c', 2.25); cout << ptr1->a << " " << ptr1->b << " " << ptr1->c << endl; block.print(); Data* ptr2 = block.getPtr<Data>(200, 'd', 122.25); cout << ptr2->a << " " << ptr2->b << " " << ptr2->c << endl; block.print(); Data* ptr3 = block.getPtr<Data>(1); cout << ptr2 << " " << ptr3 << endl; cout << ptr3->a << " " << ptr3->b << " " << ptr3->c << endl; block.print(); //注意釋放需要手動呼叫解構函式 getchar(); return 0; }

列印如下:
這裡寫圖片描述
可以看到獲取index=1的記憶體塊的資料正如我們建立的一致。

記憶體對齊

//待操作的資料
struct Data 
{
    Data(int _a, char _b, double _c) :a(_a), b(_b), c(_c) {}
    int    a;
    char   b;
    double c;

    friend ostream& operator << (ostream& out, const Data& ths)
    {
        cout << ths.a << "   " << ths.b << "   " << ths.c << endl;
        return out;
    }
};
template<class T, std::size_t N>
class AlignStorage
{
public:

    //建立記憶體對齊的物件
    template<class ...Args>
    void emplace_back(Args&& ...args)
    {
        if (m_size >= N)
        {
            throw std::bad_alloc{};
        }
        new(data + m_size) T(std::forward<Args>(args)...);
        ++m_size;       
    }

    //訪問物件
    const T& operator[](std::size_t pos) const
    {
        return *reinterpret_cast<const T*>(data + pos);
    }

    //刪除物件
    ~AlignStorage()
    {
        for (std::size_t pos = 0; pos < m_size; ++pos)
        {
            reinterpret_cast<T*>(data + pos)->~T();    //手動呼叫解構函式
        }
    }
private:
    std::size_t         m_size = 0;
    //N個T型別對齊的且未初始化的資料
    typename std::aligned_storage<sizeof(T), alignof(T)>::type data[N];
};

原理上來說兩者方式是一樣的。但是使用記憶體對齊的好處是:

  1. 平臺原因(移植原因):不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址處取某些特定型別的資料,否則丟擲硬體異常。
  2. 效能原因:經過記憶體對齊後,CPU的記憶體訪問速度大大提升。