不调用对象的析构器是未定义的行为吗?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了不调用对象的析构器是未定义的行为吗?相关的知识,希望对你有一定的参考价值。

这似乎是一个显而易见的问题,但是我一直没有找到明确的答案。请看下面的代码。

{
    std::aligned_storage_t<sizeof(int), alignof(int)> storage;
    int& i = *new(&storage) int;
}

在这里,我启动了一个名为 "对象 "的生命。i 但这一生并没有明确的 "结束",因为不应该有任何的呼唤 ~int.我不知道这个问题的答案是否取决于类型是否琐碎,所以我将提供这第二个例子。


class MyMem : public std::pmr::memory_resource
{
    std::size_t mem_size = 0u;
    char* mem_handle = nullptr;

    virtual void* do_allocate(std::size_t bytes, std::size_t) final
    {
        mem_size += bytes;
        mem_handle = static_cast<char*>(std::realloc(mem_handle, mem_size));
        return mem_handle + mem_size - bytes;
    }
    virtual void do_deallocate(void*, std::size_t, std::size_t) final {}
    virtual bool do_is_equal(const std::pmr::memory_resource&) const noexcept { return false; }

public:
    void* data() const noexcept { return mem_handle; }
};

//...
MyMem mbr;
{
    std::aligned_storage_t<sizeof(std::pmr::vector<int>), alignof(std::pmr::vector<int>)> vec_storage;
    auto& vec = *new(&vec_storage) std::pmr::vector<int>(&mbr);
    vec.resize(N);
}
// Free the data here
std::free(mbr.data());

使用一个自定义的内存资源,我可以得到一个句柄 到数据分配的调用到 vector::resize 并确保我们不会泄露内存。然而实际的destructor调用的是 vector 缺少,因此每个 int 对象分配在该内存中。

答案

不,这不是未定义的行为。一个对象的析构器不需要被调用。(C++标准例子)

N.B: 然而,在你的例子中,由 placement new 表达式创建的 int 对象的生命期在结束括号处结束。如果一个对象的析构器被调用,或者它的存储被释放或重新使用,那么这个对象的生命期就结束了。[基本生活]1:

{
  std::aligned_storage_t<sizeof(int), alignof(int)> storage;
  int& i = *new(&storage) int;
} // storage released => end of life of the int.

{
  std::aligned_storage_t<sizeof(std::pmr::vector<int>),
                                alignof(std::pmr::vector<int>)> vec_storage;
  auto& vec = *new(&vec_storage) std::pmr::vector<int>(&mbr);
  vec.resize(N);
} // end of life of the vector, without destructor call

{
  std::aligned_storage_t<sizeof(std::pmr::vector<int>),
                                alignof(std::pmr::vector<int>)> vec_storage;
  auto& vec = *new(&vec_storage) std::pmr::vector<int>(&mbr);
  vec.resize(N);
  // next statement end the life of the vector refered by vec, no destructor called
  auto& vec2 = *new(&vec_storage) std::pmr::vector<int>(&mbr);
} // end of life of the vector referred by vec2, no destructor called

N.B.2:在最后一个块中,由于没有调用destructor,你会有内存泄漏。但允许内存泄漏。

以上是关于不调用对象的析构器是未定义的行为吗?的主要内容,如果未能解决你的问题,请参考以下文章

删除 null void* 指针是未定义的行为吗?

当派生类的析构函数是虚拟的而基类的 dtor 不是时代码崩溃

返回一个对象会调用它的析构函数吗?

C ++中的析构函数调用顺序[重复]

在一个派生类对象结束其生命周期时析构函数的调用顺序

继承机制中的构造器和析构器