无需调用析构函数即可结束STL容器的生存期

埃弗拉德

问题

C ++ 11标准是否允许在不调用其析构函数的情况下结束容器(例如std :: map)的生存期,如果此类容器不需要调用其包含的元素的析构函数并且内存不需要被释放(使用Allocator :: deallocate)。

深度说明

C ++ 11标准规定以下内容:

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

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

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

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

我想知道,如果标准允许使用std :: map并在不调用destructor的情况下终止其生存期例如,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
埃弗拉德

我在这里提出了这个问题: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标准中)。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

异步函数调用的参数生存期

来自分类Dev

Rust生存期和调用成员函数

来自分类Dev

Rust生存期和调用成员函数

来自分类Dev

范围结束之前调用的析构函数

来自分类Dev

范围结束之前调用的析构函数

来自分类Dev

为什么函数参数的生存期与函数内部绑定的生存期不同?

来自分类Dev

调用返回引用的函数时了解非词汇生存期

来自分类Dev

析构函数调用

来自分类Dev

应该在stl容器调用其值的析构函数之前还是之后终止所有权?

来自分类Dev

在自定义容器中调用析构函数

来自分类Dev

在自定义容器中调用析构函数

来自分类Dev

调用AWS Cognito GetCredentialsForIdentity时指定sessionToken生存期

来自分类Dev

构造函数注入Autofac的InstancePerDependency的生存期

来自分类Dev

将生存期参数限制为函数参数的范围

来自分类Dev

如何使用impl函数声明枚举生存期?

来自分类Dev

将变量传递给函数和生存期

来自分类Dev

从`String`中获取`&'a str`的生存期比当前函数更长

来自分类Dev

泛型函数中的Rust生存期问题

来自分类Dev

函数内部局部变量的生存期如何延长?

来自分类Dev

从函数返回的迭代器的生存期要求冲突

来自分类Dev

构造函数注入Autofac的InstancePerDependency的生存期

来自分类Dev

从析构函数调用BeginInvoke

来自分类Dev

Cassandra会话生存期

来自分类Dev

ReactiveUI ObservableForProperty生存期

来自分类Dev

StructureMap生存期范围

来自分类Dev

StructureMap生存期范围

来自分类Dev

如何绕过成员函数结束时对析构函数的调用?

来自分类Dev

如何绕过成员函数结束时对析构函数的调用?

来自分类Dev

std:map析构函数会调用键析构函数还是值析构函数?

Related 相关文章

热门标签

归档