为什么隐式调用析构函数?

发布于 2025-01-19 20:40:18 字数 4005 浏览 0 评论 0原文

相关?:为什么被称为Destructor对于未删除的对象?

作为最小情况,我有一个模板堆积的仅移动值类模板。我不明白的是,为什么只使用其noexcept move-constructor的函数似乎想使用其d'tor:

#include <cassert>
#include <memory>

// Roughly a unique_ptr:
template <typename T>
class move_only_heap_value {
    T* ptr;
public:
    move_only_heap_value() : ptr(new T()) {}
    move_only_heap_value(move_only_heap_value&& x) noexcept : ptr(x.ptr) { x.ptr = nullptr; }
    // ...
    T& operator*() { assert(ptr); return *ptr; }
    const T& operator*() const { assert(ptr); return *ptr; }
    // ...

    ~move_only_heap_value() {
        if (ptr) {
            delete ptr;
        }
    }
};

//struct S {    S();    ~S();  }; // I don't see ~S() called anywhere.
struct S;

move_only_heap_value<S> foo(move_only_heap_value<S>&& x) {
    return std::move(x); // Error here due to missing ~move_only_heap_value<S>()
}

asues

<source>: In instantiation of 'move_only_heap_value<T>::~move_only_heap_value() [with T = S]':
<source>:27:21:   required from here
<source>:18:13: error: possible problem detected in invocation of 'operator delete' [-Werror=delete-incomplete]
   18 |             delete ptr;
      |             ^~~~~~~~~~
<source>:18:20: error: invalid use of incomplete type 'struct S' [-Werror]
   18 |             delete ptr;
      |                    ^~~
<source>:24:8: note: forward declaration of 'struct S'
   24 | struct S;
      |        ^
<source>:18:13: note: neither the destructor nor the class-specific 'operator delete' will be called, even if they are declared when the class is defined
   18 |             delete ptr;
      |             ^~~~~~~~~~
cc1plus: all warnings being treated as errors
ASM generation compiler returned: 1
<source>: In instantiation of 'move_only_heap_value<T>::~move_only_heap_value() [with T = S]':
<source>:27:21:   required from here
<source>:18:13: error: possible problem detected in invocation of 'operator delete' [-Werror=delete-incomplete]
   18 |             delete ptr;
      |             ^~~~~~~~~~
<source>:18:20: error: invalid use of incomplete type 'struct S' [-Werror]
   18 |             delete ptr;
      |                    ^~~
<source>:24:8: note: forward declaration of 'struct S'
   24 | struct S;
      |        ^
<source>:18:13: note: neither the destructor nor the class-specific 'operator delete' will be called, even if they are declared when the class is defined
   18 |             delete ptr;
      |             ^~~~~~~~~~
cc1plus: all warnings being treated as errors
Execution build compiler returned: 1

https://godbolt.org/z/komrcm1n4

我理解为什么此翻译单元不能调用〜move> 〜move_only_heap_value&lt因为s是不完整的),但是有什么要说的是什么?如果我改为定义s,但请将其c'tor and d'tor nordection保留,我会按预期获得链接错误,但我看不到d't tor在大会中呼叫,所以为什么会这样认为需要实例化吗?

一个更简单但可能略有不同的情况:

#include <utility>

struct Indestructible {
    Indestructible() = default;
    Indestructible(Indestructible&& x) noexcept = default;
    ~Indestructible() = delete;
};

Indestructible foo(Indestructible&& x) {
    return std::move(x);
}

生产

<source>: In function 'Indestructible foo(Indestructible&&)':
<source>:10:21: error: use of deleted function 'Indestructible::~Indestructible()'
   10 |     return std::move(x);

https://godbolt.org.org.org.org/z/mbkhqddxd 但是我担心这是不同的,因为也许返回的结果具有自动存储持续时间,因此将来必须在某个序列上破坏,但不可破坏,而原始版本可能会破坏,只是在此翻译单元中。

Related?: Why is the destructor called for an object that is not deleted?

As a minimal case, I have a templated heap-allocated move-only value class template. What I don't understand is why a function that just uses its noexcept move-constructor seems to want to use its d'tor:

#include <cassert>
#include <memory>

// Roughly a unique_ptr:
template <typename T>
class move_only_heap_value {
    T* ptr;
public:
    move_only_heap_value() : ptr(new T()) {}
    move_only_heap_value(move_only_heap_value&& x) noexcept : ptr(x.ptr) { x.ptr = nullptr; }
    // ...
    T& operator*() { assert(ptr); return *ptr; }
    const T& operator*() const { assert(ptr); return *ptr; }
    // ...

    ~move_only_heap_value() {
        if (ptr) {
            delete ptr;
        }
    }
};

//struct S {    S();    ~S();  }; // I don't see ~S() called anywhere.
struct S;

move_only_heap_value<S> foo(move_only_heap_value<S>&& x) {
    return std::move(x); // Error here due to missing ~move_only_heap_value<S>()
}

produces

<source>: In instantiation of 'move_only_heap_value<T>::~move_only_heap_value() [with T = S]':
<source>:27:21:   required from here
<source>:18:13: error: possible problem detected in invocation of 'operator delete' [-Werror=delete-incomplete]
   18 |             delete ptr;
      |             ^~~~~~~~~~
<source>:18:20: error: invalid use of incomplete type 'struct S' [-Werror]
   18 |             delete ptr;
      |                    ^~~
<source>:24:8: note: forward declaration of 'struct S'
   24 | struct S;
      |        ^
<source>:18:13: note: neither the destructor nor the class-specific 'operator delete' will be called, even if they are declared when the class is defined
   18 |             delete ptr;
      |             ^~~~~~~~~~
cc1plus: all warnings being treated as errors
ASM generation compiler returned: 1
<source>: In instantiation of 'move_only_heap_value<T>::~move_only_heap_value() [with T = S]':
<source>:27:21:   required from here
<source>:18:13: error: possible problem detected in invocation of 'operator delete' [-Werror=delete-incomplete]
   18 |             delete ptr;
      |             ^~~~~~~~~~
<source>:18:20: error: invalid use of incomplete type 'struct S' [-Werror]
   18 |             delete ptr;
      |                    ^~~
<source>:24:8: note: forward declaration of 'struct S'
   24 | struct S;
      |        ^
<source>:18:13: note: neither the destructor nor the class-specific 'operator delete' will be called, even if they are declared when the class is defined
   18 |             delete ptr;
      |             ^~~~~~~~~~
cc1plus: all warnings being treated as errors
Execution build compiler returned: 1

https://godbolt.org/z/KoMrcM1n4

I understand why this translation unit can't call ~move_only_heap_value<S>() (because S is incomplete), but what possess it to want to call that? If I instead define S but leave its c'tor and d'tor undefined, I get a link error as expected but I don't see the d'tor called in the assembly, so why does it think it needs to instantiate it?

A simpler case, but possibly subtly different:

#include <utility>

struct Indestructible {
    Indestructible() = default;
    Indestructible(Indestructible&& x) noexcept = default;
    ~Indestructible() = delete;
};

Indestructible foo(Indestructible&& x) {
    return std::move(x);
}

produces

<source>: In function 'Indestructible foo(Indestructible&&)':
<source>:10:21: error: use of deleted function 'Indestructible::~Indestructible()'
   10 |     return std::move(x);

https://godbolt.org/z/MbKhqddxd
but I worry that's different since maybe the returned result has automatic storage duration and so has to be destructed at some sequence point in the future but is not destructible, whereas the original version can be destructed, just not in this translation unit.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

梦明 2025-01-26 20:40:18

但是有什么资格这么称呼它呢?

您可以在此处删除指向该类型对象的指针。

<前><代码>~move_only_heap_value() {
如果(指针){
删除指针;
// ^^^^^^^^^^
}
}

这将调用析构函数,并且必须在此时定义类型。模板的 ~move_only_heap_value 又已被实例化,因为您定义了一个返回该模板实例的对象的函数。

您可以删除此析构函数的定义,它将编译。您可以在定义 S 的其他地方定义它。

但我没有看到大会中调用了 d'tor

仅仅因为某些东西不会在程序集中结束,并不一定意味着它不需要被明确定义。


PS if (ptr) delete ptr; 总是可以简化为 delete ptr; 条件是多余的。

but what possess it to want to call that?

You delete a pointer to an object of that type here.

~move_only_heap_value() {
    if (ptr) {
        delete ptr;
//      ^^^^^^^^^^
    }
}

That invokes the destructor, and the type must be defined at that point. ~move_only_heap_value of the template in turn has been instantiated because you have defined a function that returns an object of that template instance.

You can remove the definition of this destructor, and it will compile. You can define it elsewhere in a place where S is defined.

but I don't see the d'tor called in the assembly

Just because something won't end up in the assembly, doesn't necessarily mean that it won't need to be well-defined.


P.S. if (ptr) delete ptr; can always be simplified into delete ptr; The condition is redundant.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文