c++ - 有没有办法让一组未初始化的类在调用 delete[] 时不会被破坏?

标签 c++ memory-leaks destructor delete-operator type-erasure

我正在实现一个带有删除类型的对象池,这样池就可以存储在集合中,也可以存储其他池。该功能已到位,但还存在由于未删除池本身而导致的内存泄漏。我有以下代码:

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/

相关文章:

c++ - (修订)prefix++和postfix++有什么区别?

c++ - 在 vector 中存储字符指针,C++

新旧样式类中的 Python 析构函数

c# - 无法使用 ANTS 内存分析器检测内存泄漏

objective-c 内存友好的背景图像方式

c++ - 使用*指针数组 C++ 设置构造函数和析构函数

c++ - 使用 RAII 写入文件结束标记?

c++ - 处理 C++ "initialized but not referenced"警告以销毁作用域助手?

c++ - 放置新的覆盖现有对象

c++ - C++ 类型中有哪些不能被复制?