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

标签 c++ c++11 containers

我正在设计一个像这样的自定义 C++ 模板容器:

template <class C>
class Container {
public:
    ...
    void clear() {
        // should I call destructor on elements here?
        for (i...)
            array[i].~C(); // ?
    }

    ~Container() {
        delete [] array_;
    }
private:
    C* array_;
};

我应该在 clear() 中手动调用元素的析构函数吗?如果我不这样做,它们将在稍后容器被销毁时被调用(因为我在析构函数中删除了 [] array_),但这不是预期的行为(我们希望它们在 clear() 内部被销毁,就像 std::vector 确实如此)。 但是,如果我确实调用了析构函数,那 block 内存仍然存在,并且当我将在旧元素(现在已被销毁)之上添加新元素时,将对那些被销毁的元素调用赋值运算符,这可能会导致在未定义的行为中。 假设我有一个类:

class Foo {
public:
    Foo() { foo_ = new int; }
    ~Foo() { delete foo_; } // note I don't explicitly set foo_ to nullptr here
    Foo(Foo &&f) {
        f.foo_ = std::exchange(foo_, f.foo_); // standard practice in move constructors
    }
};

好的,到目前为止这看起来不错,但现在如果我做一个

Container<Foo> c;
c.add(Foo());
c.clear();
c.add(Foo());

当调用 clear() 时,初始 Foo 的析构函数被调用,使其 foo_ 指针悬空。接下来,当添加第二个 Foo 时,临时 R 值与被析构对象的旧内容交换,当 temp 将被销毁时,其析构函数将再次尝试删除相同的悬空指针,这将崩溃。

那么,如何正确地 clear() 容器而不为双重删除留出空间? 我还读到它建议不要在析构函数中将指针设置为 nullptr,以免隐藏潜在的悬挂指针问题。

我对如何处理这个问题有点困惑。

编辑:--------------------

对于模板容器,似乎没有不妥协的方法。 到目前为止,我看到了这些选项,正如其他人指出的那样:

  1. 彻底删除clear()中的底层数组;这将是 安全但性能不佳。但是我不能使用这个选项,因为我 实现无锁多线程容器。
  2. 我不会调用 clear() 中元素的析构函数,而是调用默认构造函数:array[i] = C();这似乎 就像迄今为止最好的解决方案 - 除了它仍然意味着额外的 默认构造。
  3. 在 add() 中使用 placement new - 这似乎适用于复制构造。 但是,移动构造到未初始化的对象中似乎仍然存在问题,因为大多数移动构造函数都是通过指针之间的交换实现的——这会使源对象(移动自)无效。

最佳答案

delete [] array_ 将为 array_ 的每个元素调用析构函数(假设 C 是具有析构函数的类型)。

在任何给定对象上两次调用析构函数会产生未定义的行为。

这意味着您的 clear() 成员函数不应直接调用数组元素的析构函数。

如果您坚持要有一个单独的 clear() 函数,它不会干扰析构函数的工作,只需将其实现为

void clear()
{
    delete [] array_;
    array = nullptr;       //  NULL or 0 before C++11
}

这不会干扰析构函数,因为操作符 delete 对 NULL 指针没有影响。

关于c++ - 在自定义容器中调用析构函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38170687/

相关文章:

Python + setuptools : distributing a pre-compiled shared library with boost. python 绑定(bind)

c++ - 为 Raspberry pi 2 预编译 amazon-kinesis-video-streams-producer-sdk-cpp

C++11 可变参数模板函数调用转发

c++ - C 程序中需要 LVALUE 作为赋值的左操作数

c++ - boost spirit v2 编译错误 - 尝试将符号用于稍微难一些的东西并且在某处遗漏了一个重要点

c++ - 为什么在 C++11 中不删除具有副作用未定义行为的析构函数的对象?

c++ - 初始化容器中对象的正确方法/模式

docker - Kubernetes - pod 内每个容器一个请求

c++ - 没有模板参数的模板类的容器

c++ - 如何从 C++ 程序中的容器类中删除第一个元素?