删除静态向量中的唯一类对象指针

时间:2018-06-09 13:11:23

标签: c++

假设我们创建一个名为Window的简单类,并希望使用std::unique_ptr向量跟踪我们拥有的所有窗口:

#include <vector>
#include <memory>

class Window {
public:
    static std::vector<std::unique_ptr<Window>> MemberPointers;
private:
    int width;
    int height;

};

我们在此类的构造函数中为创建的对象分配指针。

根据Bjarne Stroustrup&#34; A Tour of C ++&#34;,std::unique_ptr在超出范围时会被解除分配,就像常规的局部变量一样。这是否意味着,在这个类的解构函数中,我不需要向delete调用指向该对象的vector元素?

如果没有,我怎么能用std::erasestd::remove_if删除正确的对象?

2 个答案:

答案 0 :(得分:3)

你误解了unique_ptr的目的。 它假定它持有指针的对象由new分配, 和delete在析构函数中的那个对象。例如:

void f() {
    std::unique_ptr<int> ptr{new int(123)};
} //the int allocated by new is deleted here by ptr's dtor

假设你实现了这样的类:

class Window {
public:
    Window(int w, int h) :width{w}, height{h}
    {
        MemberPointers.emplace_back(this);
    }
    static std::vector<std::unique_ptr<Window>> MemberPointers;
private:
    int width;
    int height;
};

然后,在main中,您执行此操作:

Window win{1000, 500};

现在Window::MemberPointers包含一个元素: unique_ptr持有&win

最后,整个程序完成后, 并呼叫MemberPointers的dtor。 unique_ptr尝试delete win。 请注意,win未分配new, 因此导致未定义的行为。

要点:
您的目的是从MemberPointers 中删除指针本身 当指针被破坏时, 但事实是它试图delete指针, 将指针本身留在MemberPointers中。

正确的设计很简单:没有unique_ptr s。

class Window {
public:
    Window(int w, int h) :width{w}, height{h}
    {
        MemberPointers.emplace_back(this);
    }
    ~Window()
    {
        auto p = std::remove(MemberPointers.begin(), MemberPointers.end(), this);
        MemberPointers.erase(p, MemberPointers.end());
    } // remove this from MemberPointers
    static std::vector<Window*> MemberPointers;
private:
    int width;
    int height;
};

或者,使用std::set

,效果更好,效率更高
class Window {
public:
    Window(int w, int h) :width{w}, height{h}
    {
        MemberPointers.emplace(this);
    }
    ~Window()
    {
        MemberPointers.erase(this);
    } // remove this from MemberPointers
    static std::set<Window*> MemberPointers;
private:
    int width;
    int height;
};

std::vector的设计具有复杂度O( n ),其中 n 是对象的数量; std::set的设计具有复杂度O(log( n ))(如果您创建了大量对象,效率会明显提高)。

答案 1 :(得分:1)

是,std::erasestd::remove_if以及从std::vector(包括析构函数)中删除元素的任何其他函数,调用它们删除的每个元素的析构函数。

调用unique_ptr的析构函数,销毁它指向的对象。 这可以通过超出范围(如果它在堆栈中)或显式删除指向它的指针(如果它在堆中)来发生。

在这种情况下,MemberPointers向量将在程序终止之前被销毁,这将调用其元素的析构函数(在堆上分配的unique_ptr),因此没有内存将被泄露了。