Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/130.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/drupal/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 在不调用析构函数的情况下结束STL容器的生存期 问题_C++_C++11_Standards Compliance - Fatal编程技术网

C++ 在不调用析构函数的情况下结束STL容器的生存期 问题

C++ 在不调用析构函数的情况下结束STL容器的生存期 问题,c++,c++11,standards-compliance,C++,C++11,Standards Compliance,C++11标准是否允许结束容器的生命周期 (例如,std::map)而不调用其析构函数(如果有) 容器不需要调用它所属元素的析构函数 包含和内存不需要解除分配(使用 分配器::取消分配) 深入解释 C++11标准规定了以下内容: 程序可以通过重用对象占用的存储,或者通过显式调用具有非平凡析构函数的类类型的对象的析构函数,来结束任何对象的生存期。对于具有非平凡析构函数的类类型的对象,在重用或释放该对象占用的存储之前,程序不需要显式调用析构函数;但是,如果没有显式调用析构函数,或者如果没有使用删除表

C++11标准是否允许结束容器的生命周期 (例如,std::map)而不调用其析构函数(如果有) 容器不需要调用它所属元素的析构函数 包含和内存不需要解除分配(使用 分配器::取消分配)

深入解释 C++11标准规定了以下内容:

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

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

但是像std::map、std::list等STL容器呢。? 该标准规定,一致性实现必须遵循“假设”规则。只要可观察到的行为是相同的,实现可能会有所不同

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

我想知道,标准是否允许它在不调用析构函数的情况下使用std::map并结束其生命周期。例如,std::map使用自定义分配器。这个分配器使用一些内存池,并且释放内存不需要释放函数。由于容器中的所有内存都是使用此分配器获得的,因此使用此类容器的程序不依赖于析构函数的副作用

代码:

类内存工具
{
公众:
...
//预先分配内存。
//成功时返回true。
bool初始化(uint32\u t大小)
{
...
}
//从预先分配的区域返回正确对齐的内存块。
模板T*分配(大小n=1)
{
...
}
...
};
模板类自定义分配器
{
公众:
CustomAllocator(MemoryPool和MemoryPool):MemoryPool(和MemoryPool){}
...
/*此分配器从内存池获取内存*/
分配(大小)
{
返回内存工具->分配(n);
}
//此函数可能是无操作的,它取决于
//内存池。这在这个问题的上下文中并不重要。
//无论如何,所有内存都已在内存池中分配,因此
//是否需要标记未使用的块取决于实际应用程序。
无效释放(T*,size_T){}
...
私人:
MemoryPool*MemoryPool_u2;;
...
};
MemoryPool MemoryPool;
memoryPool.initialize();
//我故意在这个映射中只使用基本类型
//因为没有调用这些对象的析构函数
//不会导致未定义的行为
typedef std::map
<
uint32_t,uint32_t,
std::更少,
客户分配器
>SomeMap;
SomeMap*SomeMap=memoryPool.allocate();
新的(someMap)someMap(CustomAllocator{memoryPool});
//没有调用SomeMap的析构函数
//内存在内存池的析构函数中解除分配

我在这里问了这个问题:

根据17.5.2.3/1:

条例草案第18至30条及附件D并无指明类别的表示,并故意略去 类别成员规范(9.2)。实现可以定义静态或非静态类成员,或者 二者都是根据需要实现第18条至第30条中规定的成员函数的语义,以及 附件D


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

您将实际问题隐藏在哪里了?我已经突出显示了一些句子。我相信这种情况的通常做法是使分配器的
释放()
a no-op.To-Mat:这与malloc和free无关。这是关于std::map析构函数的副作用。在上面的示例中,池中的所有内存都已预分配(使用运算符new)。基本上,在MemoryPool::initialize中有类似于storage的东西。运算符delete是从MemoryPool的析构函数中调用的。这就是为什么不需要从容器中释放内存的原因。@Mat问题在于是否定义好了不调用
map
的析构函数。如果你真的调用了析构函数,那么最终将执行大量的工作(清理它自己的内部),而这些工作在OP的情况下最终是无用的,因此询问是否允许省略对析构函数的调用对我来说是一个公平的问题。
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