在哪些情况下应该删除指针
In Which Situations To Delete A Pointer
我下面的问题是关于内存管理的。例如,我有一个int变量,不是在类中动态分配的,我们设为invar1。我把这个的内存地址传递给另一个类的构造函数。这个类的作用是:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
我应该删除点吗?因为它有一个不动态分配的int的地址,我想我不需要删除它。
我又用new操作符声明了一个类的对象:
objtoclass = new ex1();
我把它传递给另一个类:
class ex2{
ex2(ex1* p_obj)
{
obj = p_obj;
}
ex1* obj;
};
我应该删除obj时,我已经删除objtoclass?
谢谢!
因为它有一个不动态分配的int的地址,所以我想我不需要删除它。
正确的。
号我应该删除obj时,我已经删除objtoclass?
记住,你实际上并不是在删除指针;你用指针来删除它们指向的东西。因此,如果您同时写入delete obj
和delete objtoclass
,因为两个指针都指向同一个对象,您将删除该对象两次。
我要提醒你,这是一个非常容易犯的错误,你的ex2
类,其中指向对象的所有权语义并不完全清楚。您可以考虑使用智能指针实现来消除风险。
只是其他答案的附录
在智能指针(shared_ptr
, unique_ptr
)的帮助下,您可以摆脱原始指针,忘记内存管理。
智能指针在超出作用域时负责释放内存。
下面是一个例子:
#include <iostream>
#include <memory>
class ex1{
public:
ex1(std::shared_ptr<int> p_intvar1)
{
ptoint = p_intvar1;
std::cout << __func__ << std::endl;
}
~ex1()
{
std::cout << __func__ << std::endl;
}
private:
std::shared_ptr<int> ptoint;
};
int main()
{
std::shared_ptr<int> pi(new int(42));
std::shared_ptr<ex1> objtoclass(new ex1(pi));
/*
* when the main function returns, these smart pointers will go
* go out of scope and delete the dynamically allocated memory
*/
return 0;
}
输出:ex1
~ex1
我应该删除obj时,我已经删除objtoclass?
好吧,你可以,但要注意,删除同一个对象两次是未定义的行为,应该避免。这可能会发生,例如,如果你有两个指针指向同一个对象,你用一个指针删除原始对象,那么你不应该用另一个指针删除内存。在你的情况下,你最终可能会有两个指针指向同一个对象。
一般来说,构建一个在内部管理内存的类(就像你表面上做的那样)并不是微不足道的,你必须考虑到像三规则之类的事情。
关于应该删除动态分配的内存,你是对的。如果内存不是动态分配的,那么不应该删除内存。
p。为了避免上述的复杂情况,你可以使用智能指针。
当前没有删除这个int,也没有显示它的分配位置。如果两个对象都不应该拥有它的形参,我就写
struct ex1 {
ex1(int &i_) : i(i_) {}
int &i; // reference implies no ownership
};
struct ex2 {
ex2(ex1 &e_) : e(e_) {}
ex1 &e; // reference implies no ownership
};
int i = 42;
ex1 a(i);
ex2 b(a);
如果其中一个参数被假定为新对象所拥有的,则将其作为unique_ptr
传递。如果其中一个参数应该是共享的,则使用shared_ptr
。我通常更喜欢这些(引用或智能指针)而不是原始指针,因为它们提供了更多关于您意图的信息。
一般来说,为了做出这些决定,
我应该删除点吗?
是错误的问题。首先考虑稍微高一些的层次:
- 这个int在程序中表示什么?
- 谁拥有它,如果有人的话?
- 与使用它的类相比,它应该存活多长时间?
,然后看看这些例子的答案是如何自然地得出的:
这个int是一个I/O映射控制寄存器。
在这种情况下,它不是用
new
创建的(它存在于整个程序之外),因此你当然不应该删除它。它可能还应该标记为volatile
,但这并不影响生命周期。也许你的类之外的某些东西映射了地址,也应该取消映射,这类似于(取消)分配它,或者它只是一个众所周知的地址。
this int是一个全局日志级别。
在这种情况下,它可能具有静态生存期,在这种情况下,没有人拥有它,它没有被显式分配,因此不应该显式地取消分配
或者,它由一个日志对象/singleton/mock/等等拥有,并且该对象负责在必要时释放它
this int被显式地给定给你的对象来拥有
在这种情况下,让它变得明显是一个好习惯,例如:
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
请注意,将本地数据成员设置为
unique_ptr
或类似的值,也会自动处理生命周期,而不需要您做任何努力。这个int是给你的对象使用,但其他对象也可能使用它,这是不明显的顺序,他们将完成
用
shared_ptr<int>
代替unique_ptr
来描述这个关系。同样,智能指针将为您管理生命周期。
如果您不能在类型中编码该信息,您至少可以清楚地表明您的意图:事实上,您询问了重新分配而没有提及生命周期或所有权,这表明您在错误的抽象级别上工作。
因为它有一个未动态分配的整型对象的地址,所以I我想我不需要删除它。
正确。请不要删除。
你问题的第二部分是关于动态分配内存的。在这里,你必须多考虑一点,做出一些决定。
假设你的类ex1在它的构造函数中接收到一个原始指针,该指针指向在类外部动态分配的内存。
作为类的设计者,你必须决定这个构造函数"是否获得这个指针的所有权"。如果是这样,那么ex1负责删除其内存,您应该在类析构函数中执行此操作:
class ex1 {
public:
/**
* Warning: This constructor takes the ownership of p_intvar1,
* which means you must not delete it somewhere else.
*/
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
~ex1()
{
delete ptoint;
}
int* ptoint;
};
然而,这通常是一个糟糕的设计决策。您必须为该类的用户root,阅读构造函数的注释,并记住不要删除在类ex1之外分配的内存。
接收指针并获取其所有权的方法(或构造函数)称为"sink"。
有人会这样使用这个类:
int* myInteger = new int(1);
ex1 obj(myInteger); // sink: obj takes the ownership of myInteger
// never delete myInteger outside ex1
另一种方法是说你的类ex1不占有指针的所有权,为该指针分配内存的人负责删除它。类ex1不能删除其析构函数中的任何内容,它应该这样使用:
int* myInteger = new int(1);
ex1 obj(myInteger);
// use obj here
delete myInteger; // remeber to delete myInteger
同样,你的类的用户必须阅读一些文档,以便知道他是负责删除的东西。
如果你不使用现代c++,你必须在这两种设计决策中做出选择。
在现代c++ (c++ 11和c++ 14)中,你可以在代码中显式地写东西(也就是说,不必只依赖于代码文档)。
首先,在现代c++中避免使用原始指针。您必须在两种"智能指针"之间做出选择:unique_ptr或shared_ptr。它们之间的区别在于所有权。
顾名思义,唯一指针只能由一个人拥有,而共享指针可以由一个或多个人拥有(所有权是共享的)。
唯一指针(std::unique_ptr)不能复制,只能从一个位置"移动"到另一个位置。如果一个类有一个唯一的指针作为属性,则显式地表示该类拥有该指针的所有权。如果一个方法接收到一个唯一的指针作为拷贝,则明确表示它是一个"接收"方法(获取指针的所有权)。
你的类ex1可以这样写:
class ex1 {
public:
ex1(std::unique_ptr<int> p_intvar1)
{
ptoint = std::move(p_intvar1);
}
std::unique_ptr<int> ptoint;
};
这个类的用户应该这样使用它:
auto myInteger = std::make_unique<int>(1);
ex1 obj(std::move(myInteger)); // sink
// here, myInteger is nullptr (it was moved to ex1 constructor)
如果你在上面的代码中忘记执行"std::move",编译器会生成一个错误,告诉你unique_ptr是不可复制的。
还要注意,您永远不必显式地删除内存。
- 无法删除指针,已触发断点
- 删除指针数组 (C++) 中的元素
- 如果我删除指针,我的C++程序会意外删除系统文件吗?
- 为什么const_cast删除指针的恒常性,而不删除指向常量的指针的恒常性?
- 删除指针后内存泄漏
- 这是系统资源吗?(或者我怎么知道我是否需要删除指针) - 在 C++ 中使用 C
- C++ 从 2 组指针中删除指针
- 当删除 [] 指针工作时,为什么无法获得指向的数组大小?
- 在这种情况下,删除指针数组期间会发生什么?
- 在C++中删除指针数组时析构函数崩溃
- 何时/如何在使用指针后正确删除指针?
- 在C++库中,谁应该删除指针、用户或库?
- 删除指针后阻止对象使用 "this"
- 删除指针后C++尝试/捕获
- 删除指针内存分配以避免内存泄漏
- 删除指针时,未分配被释放的 C++ 指针错误
- 如何从抽象类中删除指针
- 我应该在 v8::外部手动删除指针吗?
- 删除指针
- C 如何删除指针的默认对象成员