我的以下问题是内存管理。我有一个int变量没有在类中动态分配,比如说invar1。我将此int的内存地址传递给另一个类构造函数。那个班级做到了这一点:
List<T>
我应该删除ptoint吗?因为它具有动态分配的int的地址,所以我认为我不需要删除它。
我再次向具有new运算符的类声明一个对象:
class ex1{
ex1(int* p_intvar1)
{
ptoint = p_intvar1;
}
int* ptoint;
};
我将其传递给另一个班级:
objtoclass = new ex1();
当我删除objtoclass时,我应该删除obj吗?
谢谢!
答案 0 :(得分:12)
因为它具有动态分配的int的地址,我认为我不需要删除它。
正确。
当我已经删除了objtoclass时,我应该删除obj吗?
没有
回想一下,你实际上并没有删除指针;你正在使用指针删除他们指向的东西。因此,如果您同时写了delete obj
和delete objtoclass
,因为两个指针都指向同一个对象,您将两次删除该对象。
我会提醒你,这对于你的ex2
类来说是一个非常容易犯的错误,在这个类中,该指向对象的所有权语义并不完全清楚。您可以考虑使用智能指针实现来消除风险。
答案 1 :(得分:8)
你可以借助智能指针(<?
require_once("constructor.php");
$smarty->display("page_index");
if (isset($_GET["page"])) {
$page = htmlspecialchars($_GET["page"]);
$setPageFile = "module/".$page.".php";
if (file_exists($setPageFile)) {
include($setPageFile);
} else {
$smarty->assign("alert", array(1, "Żądany moduł nie jest obsługiwany."));
}
} else {
Header("Location: login");
}
$smarty->display("page_footer");
?>
,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;
}
答案 2 :(得分:4)
当我删除objtoclass时,我应该删除obj吗?
嗯,你可以记住,两次删除同一个对象是未定义的行为,应该避免。例如,如果您有两个指针,例如指向同一个对象,并且您使用一个指针删除原始对象,则可能会发生这种情况 - 那么您也不应该使用另一个指针删除该内存。在你的情况下,你可能最终得到两个指向同一个对象的指针。
一般来说,构建一个内部管理内存的类(就像你看似的那样)并不是一件容易的事情,你必须考虑像rule of three之类的东西。
关于那个应该删除动态分配的内存是对的。如果没有动态分配内存,则不应删除内存。
PS。为了避免上述复杂情况,您可以使用智能指针。
答案 3 :(得分:2)
您目前不会删除此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
。我通常更喜欢这些(引用或智能指针)中的原始指针,因为它们提供了有关您的意图的更多信息。
一般来说,做出这些决定,
我应该删除ptoint吗?
是错误的问题。首先要考虑稍微高一些的事情:
然后看看这些例子的答案是如何自然消失的:
此int是I / O映射控制寄存器。
在这种情况下,它不是用new
创建的(它存在于整个程序之外),因此你当然不应该删除它。它也应该标记为volatile
,但这并不会影响生命周期。
也许类外的东西映射了地址,也应该取消映射,这与(de)分配它很相似,或者它可能只是一个众所周知的地址。
此int是全局日志记录级别。
在这种情况下,它可能具有静态生命周期,在这种情况下,没有人拥有它,它没有明确分配,因此不应该明确地取消分配
或者,它由logger对象/ singleton / mock / what拥有,并且该对象负责在必要时解除分配
这个int被明确地赋予你的对象
在这种情况下,明智的做法是好的,例如。
ex1::ex1(std::unique_ptr<int> &&p) : m_p(std::move(p)) {}
请注意,将您的本地数据成员设为unique_ptr
或类似,也会自动处理生命周期,而您无需付出任何努力。
这个int被赋予你的对象 use ,但是其他对象也可能正在使用它,并且它们完成的顺序并不明显。
使用shared_ptr<int>
代替unique_ptr
来描述此关系。同样,智能指针将为您管理生命周期。
通常,如果您可以在类型中对所有权和生命周期信息进行编码,则无需记住手动分配和取消分配内容的位置。这更清晰,更安全。
如果您无法对该类别中的信息进行编码,您至少可以清楚自己的意图:您在不提及生命或所有权的情况下询问释放的事实,建议您&# 39;在错误的抽象层面上工作。
答案 4 :(得分:2)
因为它具有动态分配的int的地址,我 以为我不需要删除它。
这是正确的。只是不要删除它。
问题的第二部分是关于动态分配的内存。在这里,你必须多思考一下并做出一些决定。
让我们假设你的名为 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和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不可复制。
另请注意,您永远不必显式删除内存。智能指针可以为您处理。