在不调用析构函数的情况下结束STL容器的生命周期

时间:2014-10-11 14:49:24

标签: c++ c++11 standards-compliance

问题

C ++ 11 Standard是否允许结束容器的生命周期 (std :: map,例如),不调用它的析构函数,如果是这样的话 容器不需要调用它的元素的析构函数 包含和内存不需要解除分配(使用 分配器:: DEALLOCATE)。

深度解释

C ++ 11 Standard声明如下:

  
    

程序可以通过重用对象占用的存储或通过使用非平凡的析构函数显式调用类类型的对象的析构函数来结束任何对象的生命周期。对于具有非平凡析构函数的类类型的对象,程序不需要在重用或释放对象占用的存储之前显式调用析构函数;但是,如果没有显式调用析构函数或者如果没有使用delete-expression(5.3.5)来释放存储,则不应该隐式调用析构函数,并且任何程序都依赖于析构函数产生的副作用有未定义的行为。

  

这是明确而直截了当的。 例如,有一些对象在其生命周期内分配内存并在销毁时释放内存。如果程序依赖于释放内存,那么不调用对象的析构函数会导致未定义的行为。另一方面,如果object从某个内存池中获取内存,则不需要调用析构函数,因为程序不依赖于它的副作用,并且行为是明确定义的。

但是std :: map,std :: list等STL容器呢? 符合实现的标准状态必须遵循AS-IF规则。只要可观察行为相同,实施可能会有所不同。

我试图说,例如,如表96(容器要求)中所述,容器的析构函数应调用其元素的析构函数并释放所有内存。但如果它内部也使用了一些互斥量呢?标准不禁止在容器内使用一个(我错了吗?)。不调用互斥体的析构函数可能会导致未定义的行为。

我想知道,如果标准允许使用std :: map并结束其生命周期而不调用析构函数。例如,std :: map使用自定义分配器。此分配器使用一些内存池并释放内存,不需要解除分配功能。由于容器中的所有内存都是使用此分配器获取的,因此使用此类容器的程序不依赖于析构函数的副作用。

代码:

class MemoryPool
{
public:
    ...

    // Pre-allocates memory.
    // Returns true on success.
    bool initialize(uint32_t size)
    {
        ...
    }

    // Returns properly aligned block of memory from pre-allocated area.
    template <class T> T* allocate(size_t n = 1)
    {
        ...
    }

    ...
};

template <class T> class CustomAllocator
{
public:
    CustomAllocator(MemoryPool& memoryPool): memoryPool_(&memoryPool) {}

    ...

    /* this allocator obtains memory from memory pool */
    T* allocate(size_t n)
    {
        return memoryPool_->allocate<T>(n);
    }

    // This function may be a no-op, it depends on the implementation of
    // memory pool. It doesn't really matter in context of this question.
    // Anyway, all memory is already allocated in memory pool, so whether there
    // is a need to mark unused chunks or not depends on actual application.
    void deallocate(T*, size_t) {}
    ...

private:
    MemoryPool* memoryPool_;
    ...
};

MemoryPool memoryPool;
memoryPool.initialize();

// I intentionally use only fundamental types in this map
// since not invoking the destructors of such objects
// will not lead to undefined behavior
typedef std::map
<
    uint32_t, uint32_t,
    std::less<uint32_t>,
    CustomAllocator<uint32_t>
> SomeMap;

SomeMap* someMap = memoryPool.allocate<SomeMap>();
new(someMap) SomeMap(CustomAllocator<uint32_t>{memoryPool});

// no destructor of SomeMap is called
// memory is deallocated in destructor of memory pool

1 个答案:

答案 0 :(得分:1)

我在这里问了这个问题:https://groups.google.com/a/isocpp.org/forum/#!topic/std-discussion/R_KPazXbE0k

根据17.5.2.3 / 1:

  

第18至30条及附件D未指明类别的表示,并故意省略   班级成员的规范(9.2)。实现可以定义静态或非静态类成员,或   两者,根据需要实现第18至30条规定的成员函数的语义   附件D.

换句话说,实现可能有一些私有成员使用除内存之外的资源。因此,无保证没有其他副作用(至少在当前的C ++ 11标准中)。