如何在C++17中用std::aligned_alloc实现DefaultAllocate函数
在C++17中用
std::aligned_alloc实现非模板内存池的DefaultAllocate函数 关于严格别名规则和类型双关的讨论已经很多,但针对对象数组的相关解释依然晦涩难懂。我希望实现一个非模板内存池类,用于存储对象数组,仅在访问时确定实际类型——可以将其看作是“迭代器为模板的非模板vector”。本次是系列问题的第三篇:如何在C++17中使用std::aligned_alloc(且不使用已被弃用的std::aligned_storage)实现DefaultAllocate()函数。
原实现代码
#include <cassert> #include <iostream> #include <type_traits> // 支持从单个double值初始化的类型 using test_t = float; // 示例函数:p指向至少包含3个test_t的序列 void load(test_t* p) { std::cout << "starting load\n"; p[0] = static_cast<test_t>(3.14); p[1] = static_cast<test_t>(31.4); p[2] = static_cast<test_t>(314.); std::cout << "ending load\n"; } // 类型双关缓冲区 // 持有一个无类型缓冲区(实际是char*),可根据用户需求存储任意类型 struct Buffer { // 缓冲区地址 char* p = nullptr; // 已存储元素数量 size_t n = 0; // 缓冲区字节大小 size_t s = 0; // 分配足够容纳N个T类型对象的char缓冲区,并默认构造它们 // 在未调用Deallocate的情况下,对已分配缓冲区调用此函数属于未定义行为 template <typename T> T* DefaultAllocate(const size_t N) { size_t RequiredSize = sizeof(std::aligned_storage_t<sizeof(T), alignof(T)>) * N; n = N; T* tmp; if (s < RequiredSize) { if (p) { delete[] p; } s = RequiredSize; std::cout << "Requiring " << RequiredSize << " bytes of storage\n"; p = new char[s]; // 数组形式的 placement new 默认构造 tmp = new (p) T[N]; // T* tmp = reinterpret_cast<T*>(p); // // 对于算术类型和平凡可析构类型(当不关心默认值时)可省略 // for (size_t i = 0; i < n; ++i) { // new (tmp + i) T(); // } } else { // 数组形式的 placement new 默认构造 tmp = new (p) T[N]; // T* tmp = reinterpret_cast<T*>(p); // // 对于算术类型和平凡可析构类型(当不关心默认值时)可省略 // for (size_t i = 0; i < n; ++i) { // new (tmp + i) T(); // } } return tmp; } // 析构缓冲区中的对象,但不释放缓冲区本身 template <typename T> void Deallocate() { T* tmp = reinterpret_cast<T*>(p); // 按创建的逆序析构元素 // 对于默认可析构类型可省略 for (size_t i = 0; i < n; ++i) { tmp[n - 1 - i].~T(); } n = 0; } ~Buffer() { if (p) { delete[] p; } } }; int main() { constexpr std::size_t N = 3; Buffer B; test_t* fb = B.DefaultAllocate<test_t>(N); load(fb); std::cout << fb[0] << '\n'; std::cout << fb[1] << '\n'; std::cout << fb[2] << '\n'; std::cout << alignof(test_t) << '\t' << sizeof(test_t) << '\n'; B.Deallocate<test_t>(); return 0; }
补充说明
原C++14版本代码存在对齐问题,已有改进版本;前序问题围绕对象数组的类型双关与严格别名规则、省略placement new和析构函数的可行性展开。
内容的提问来源于stack exchange,提问作者Oersted
相关产品推荐
相关产品推荐

