我正在实现一个带有删除类型的对象池,这样池就可以存储在集合中,也可以存储其他池。该功能已到位,但还存在由于未删除池本身而导致的内存泄漏。我有以下代码:
template <typename T>
struct ObjectPool::PoolModel final : PoolConcept {
PoolModel(uint size) : pool( new T[size](), [](T _[]){ /*Problem!*/}) {}
virtual ~PoolModel() {}
private:
std::unique_ptr<T[], std::function<void(T[])>> pool;
};
恰如其分地,“问题!”是我的问题所在。您可能想知道为什么我将 uinique_ptr 的默认删除替换为什么都不做的删除。这是因为池在销毁时充满了完全虚假的数据,因此当池池被销毁时(或任何携带智能指针的对象池或其他具有析构函数的对象),数组删除将调用每个类的析构函数,并且通过删除导致段错误的虚假智能指针进行跟进。所以我替换了 noop 析构函数,一切都运行良好。
因此内存泄漏。我已经摆脱了默认的删除,所以每个池对象都离开了它的池。我试过“::operator delete[](arr);”在“问题!” spot,因为它应该在不调用对象的析构函数的情况下删除一个数组,但这会产生“munmap_chunk():无效指针”。我正在尝试找到一种 c++ 方法来执行此操作,而不需要求助于 malloc 和 free。此外,我想知道是否有一种方法可以首先分配数组,而无需为每个数组成员调用默认构造函数并让它们保持未初始化状态。
最佳答案
T
数组必须始终填充有效的T
对象。没有异常(exception)。
您的问题的解决方案是不使用 T
对象数组。相反,为 n 个 T
对象分配具有适当大小和对齐方式的未初始化存储,并使用 placement-new 初始化它们。然后您将负责手动调用 T
对象的析构函数。这是 std::vector
和类似数据结构使用的解决方案:
template <typename T>
struct ObjectPool::PoolModel final : PoolConcept {
using StorageT = std::aligned_storage_t<sizeof(T), alignof(T)>;
PoolModel(uint capacity)
: pool{ std::make_unique<StorageT[]>(capacity) },
size{0},
capacity{capacity}
{}
virtual ~PoolModel() {
for (size_t i = 0; i < size; ++i) {
T* ptr = std::launder(reinterpret_cast<T*>(&pool[i]));
ptr->~T();
}
}
void insert(T obj) {
assert(capacity > size);
new (&pool[size + 1]) T{std::move(obj)};
++size;
}
private:
std::unique_ptr<StorageT[]> pool;
uint size;
uint capacity;
};
当然,因为您基本上是在重新发明一个 std::vector
,您可以只使用 std::vector
代替:
template <typename T>
struct ObjectPool::PoolModel final : PoolConcept {
PoolModel(uint capacity) {
pool.reserve(capacity);
}
virtual ~PoolModel() {}
void insert(T obj) {
pool.push_back(std::move(obj));
}
private:
std::vector<T> pool;
};
关于c++ - 有没有办法让一组未初始化的类在调用 delete[] 时不会被破坏?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56554359/