【C++】記憶體對齊和簡單的記憶體管理
阿新 • • 發佈:2019-01-26
記憶體管理
自己申請一個記憶體塊,用來存放構造的資料,使用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];
};
原理上來說兩者方式是一樣的。但是使用記憶體對齊的好處是:
- 平臺原因(移植原因):不是所有的硬體平臺都能訪問任意地址上的任意資料的;某些硬體平臺只能在某些地址處取某些特定型別的資料,否則丟擲硬體異常。
- 效能原因:經過記憶體對齊後,CPU的記憶體訪問速度大大提升。