假设我们创建一个名为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::erase
和std::remove_if
删除正确的对象?
答案 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::erase
,std::remove_if
以及从std::vector
(包括析构函数)中删除元素的任何其他函数,调用它们删除的每个元素的析构函数。
调用unique_ptr
的析构函数,销毁它指向的对象。
这可以通过超出范围(如果它在堆栈中)或显式删除指向它的指针(如果它在堆中)来发生。
在这种情况下,MemberPointers
向量将在程序终止之前被销毁,这将调用其元素的析构函数(在堆上分配的unique_ptr
),因此没有内存将被泄露了。