内存管理
自己申请一个内存块,用来存放构造的数据,使用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的内存访问速度大大提升。具体原因稍后解释。