显式析构函数

发布于 2024-10-16 05:13:39 字数 1214 浏览 4 评论 0原文

下面的代码只是用来说明我的问题。

template<class T>
class array<T>
{
 public:
    // constructor
    array(cap = 10):capacity(cap)
    {element = new T [capacity]; size =0;}

    // destructor
    ~array(){delete [] element;}
    void erase(int i);
    private:
      T *element;
      int capacity;
      int size;
};



template<class T>
void class array<T>::erase(int i){
     // copy
     // destruct object
    element[i].~T();  ////
    // other codes
} 

如果我有 array; arr 在 main.cpp 中。当我使用erase(5)时,element[5]的对象被销毁,但element[5]的空间不会被释放,我可以使用 element[5] = "abc" 在这里输入一个新值吗?或者我应该使用placement new 将新值放入element [5] 的空间中?

当程序结束时,arr将调用它自己的析构函数,该析构函数也调用delete [] element。所以string的析构函数会先销毁对象,然后释放空间。但由于我已经显式地析构了 element[5],析构函数(由 arr 的析构函数调用)运行两次来析构 element[5] 有关系吗?我知道空间不能被释放两次,那么对象呢​​?我做了一些测试,发现如果我只是破坏对象两次而不是释放空间两次似乎没问题。

更新

答案是:

(1)如果我显式调用析构函数,则必须使用placement new。

(2) 重复析构对象被定义为未定义的行为,大多数系统都可以接受,但应尽量避免这种做法。

The following code is just used to illustrate my question.

template<class T>
class array<T>
{
 public:
    // constructor
    array(cap = 10):capacity(cap)
    {element = new T [capacity]; size =0;}

    // destructor
    ~array(){delete [] element;}
    void erase(int i);
    private:
      T *element;
      int capacity;
      int size;
};



template<class T>
void class array<T>::erase(int i){
     // copy
     // destruct object
    element[i].~T();  ////
    // other codes
} 

If I have array<string> arr in main.cpp. When I use erase(5), the object of element[5] is destroyed but the space of element[5] will not be deallocated, can I just use element[5] = "abc" to put a new value here? or should I have to use placement new to put new value in the space of element [5]?

When program ends, the arr<string> will call its own destructor which also calls delete [] element. So the destructor of string will run to destroy the object first and then free the space. But since I have explicitly destruct the element[5], does that matter the destructor (which is called by the arr's destuctor) run twice to destruct element[5]? I know the space can not be deallocated twice, how about the object? I made some tests and found it seems fine if I just destruct object twice instead of deallocating space twice.

Update

The answers are:

(1)I have to use placement new if I explicitly call destructor.

(2) repeatedly destructing object is defined as undefined behavior which may be accepted in most systems but should try to avoid this practice.

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

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

发布评论

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

评论(2

兮子 2024-10-23 05:13:39

您需要使用placement-new语法:

new (element + 5) string("abc");

element[5] = "abc"; 是不正确的;这将调用 element[5] 上的 operator=,它不是一个有效的对象,从而产生未定义的行为。

当程序结束时,arr将调用它自己的析构函数,该析构函数也调用delete []元素

这是错误的:您最终将调用已调用析构函数的对象的析构函数(例如,上述示例中的 elements[5])。这也会产生未定义的行为。

考虑使用 std::allocator 及其接口。它使您可以轻松地将分配与构造分开。它由 C++ 标准库容器使用。

You need to use the placement-new syntax:

new (element + 5) string("abc");

It would be incorrect to say element[5] = "abc"; this would invoke operator= on element[5], which is not a valid object, yielding undefined behavior.

When program ends, the arr<string> will call its own destructor which also calls delete [] element.

This is wrong: you are going to end up calling the destructor for objects whose destructors have already been called (e.g., elements[5] in the aforementioned example). This also yields undefined behavior.

Consider using the std::allocator and its interface. It allows you easily to separate allocation from construction. It is used by the C++ Standard Library containers.

与之呼应 2024-10-23 05:13:39

只是为了进一步准确地解释 UD 可能会如何咬你......

如果你 erase() 一个元素 - 显式调用析构函数 - 该析构函数可能会执行诸如减少引用计数器 + 清理、删除之类的操作指针等..当你的数组<>然后析构函数执行一个删除[]元素,它将依次调用每个元素的析构函数,对于擦除的元素,这些析构函数可能会重复它们的引用计数维护、指针删除等,但这一次初始状态并不像他们预期的那样,他们的行为可能会导致程序崩溃。

因此,正如 Ben 在对 James 的回答的评论中所说,在调用数组的析构函数之前,您绝对必须使用放置 new 替换已删除的元素,这样析构函数将具有一些可以从中进行析构的合法状态。

说明此问题的最简单的 T 类型是:

struct T
{
    T() : p_(new int) { }
    ~T() { delete p_; }
    int* p_;
};

这里,由 new 设置的 p_ 值将在 erase( ),并且如果 ~array() 运行时未发生变化。要解决此问题,必须将 p_ 更改为在 ~array() 之前 delete 有效的内容 - 通过某种方式将其清除为 0 或指向 new 返回的另一个指针。最明智的方法是通过放置 new,它将构造一个新对象,为 p_ 获取新的有效值,覆盖旧的无用的内存内容。

也就是说,您可能认为可以构造重复析构函数安全的类型:例如,通过在 delete 之后将 p_ 设置为 0。这可能适用于大多数系统,但我很确定标准中有一些内容说调用析构函数两次是 UD 无论如何。

Just to explain further exactly how the UD is likely to bite you....

If you erase() an element - explicitly invoking the destructor - that destructor may do things like decrement reference counters + cleanup, delete pointers etc.. When your array<> destructor then does a delete[] element, that will invoke the destructors on each element in turn, and for erased elements those destructors are likely to repeat their reference count maintenance, pointer deletion etc., but this time the initial state isn't as they expect and their actions are likely to crash the program.

For that reason, as Ben says in his comment on James' answer, you absolutely must have replaced an erased element - using placement new - before the array's destructor is invoked, so the destructor will have some legitimate state from which to destruct.

The simplest type of T that illustrates this problem is:

struct T
{
    T() : p_(new int) { }
    ~T() { delete p_; }
    int* p_;
};

Here, the p_ value set by new would be deleted during an erase(), and if unchanged when ~array() runs. To fix this, p_ must be changed to something for which delete is valid before ~array() - either by somehow clearing it to 0 or to another pointer returned by new. The most sensible way to do that is by the placement new, which will construct a new object, obtaining a new and valid value for p_, overwriting the old and useless memory content.

That said, you might think you could construct types for which repeated destructor was safe: for example, by setting p_ to 0 after the delete. That would probably work on most systems, but I'm pretty sure there's something in the Standard saying to invoke the destructor twice is UD regardless.

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