我经常想知道,
我知道我可以使用new
关键字将同一指针作为参数传递给函数,同时创建指向对象实例的指针。就像我在Animation::newFrame
函数中的下面一样,在下面的例子中给出。
但是,我也知道,作为一般规则,我负责使用delete
为我创建的内容调用new
。
所以当我像这样调用Frame的构造函数时:
Frame* myFrame
= new Frame(new point(0,0), new point(100,100), new point(50,20));
在上面的函数调用中,使用new
创建的3个点最终释放内存的责任在哪里?
毕竟,以上3个新点并没有让我打电话给delete
的名字。
我总是假设它们属于它们被调用的函数的范围,并且它们将简单地超出函数的范围。然而,最近我一直在想也许不是这样。
我希望我在这里已经足够清楚了。
提前致谢,
盖
struct Frame
{
public:
point f_loc;
point f_dim;
point f_anchor;
//the main constructor:: Creates a frame with some specified values
Frame(point* loc, point* dim, point* anchor)
{
f_loc = loc;
f_dim = dim;
f_anchor = anchor;
}
};
struct Animation
{
public:
vector<Frame*> frameList;
//currFrame will always be >0 so we subtract 1
void Animation::newFrame(int &currFrame)
{
vector<Frame*>::iterator it;//create a new iterator
it = frameList.begin()+((int)currFrame);//that new iterator is
//add in a default frame after the current frame
frameList.insert(
it,
new Frame(
new point(0,0),
new point(100,100),
new point(50,20)));
currFrame++;//we are now working on the new Frame
}
//The default constructor for animation.
//Will create a new instance with a single empty frame
Animation(int &currFrame)
{
frameList.push_back(new Frame(
new point(0,0),
new point(0,0),
new point(0,0)));
currFrame = 1;
}
};
编辑:我忘了提到这个问题纯粹是理论上的。我知道有更好的替代原始指针,如智能指针。我只想加深对常规指针的理解以及如何管理它们。
上面的示例也取自我的一个项目,实际上是C ++ / cli和c ++混合(托管和非托管类),这就是为什么构造函数只接受point*
而不是传递值({ {1}})。因为point
是一种非托管结构,因此在托管代码中使用时,必须由我自己(程序员)管理。 :)
答案 0 :(得分:11)
澄清并经常强制执行资源所有权的语义是程序员的责任。这可能是一件棘手的事情,尤其是当您在这里处理原始指针时,在资源所有权尚未给予任何实际设计考虑的环境中。后者不仅在新手程序员编写的玩具程序中很普遍,而且在具有数十年经验的人所编写的生产系统中应该更为人所知。
在上面的实际案例中,Frame
对象本身必须负责delete
传入的3个指针,并且构造Frame
本身必须负责{{1}那个。
由于资源所有权是一个雷区,程序员很久以前发明了许多技术来澄清所有权的语义,并使粗略的程序员引入错误和泄漏变得更加困难。现在,在C ++中,它被认为是避免原始指针的最佳实践,事实上,只要有可能,就会完全动态分配 - 主要是因为资源所有权是一个非常危险的雷区。
在C ++中,用于实现这些目标的主要习惯是RAII,使用的主要工具是delete
(C ++ 03),auto_ptr
,unique_ptr
及其同类。 Boost还提供了许多所谓的“智能指针”。其中许多与C ++ 11中发现的并行(事实上,C ++ 11中的新智能指针最初是由Boost开发的),但也有一些超越了,例如shared_ptr
。
答案 1 :(得分:2)
首先,您的代码需要修复以使其编译 - 例如,您可能无法将point*
分配给point
(取决于point
的实现)
完成后,您的问题的答案是Animation
需要释放frameList
中的所有内容,而Frame
需要释放传入的point*
shared_ptr
1}}秒。不会删除原始指针。
更好的答案(虽然不是你要求的)是你应该使用unique_ptr
或frameList
来管理内存 - 这些将删除指向对象。这绝对是我为std::vector<std::shared_ptr<Frame>>
所做的 - 让它成为point
。
在这种情况下,可能没有充分的理由使用{{1}}的指针(我猜它们只是坐标,并且复制起来非常便宜) - 我只是按值传递它们或const引用。这样就没有涉及堆分配,而且更加简单。
答案 2 :(得分:1)
垃圾收集器,智能指针,有时它是自动的(如果从堆栈中分配)。基本上,是你负责,但你可以将责任委托给其他人。
答案 3 :(得分:1)
如果您正在调用的函数没有明确说明它将在完成时获取传递指针delete
的所有权,那么您自己delete
对new
任何事情负责。
答案 4 :(得分:1)
正如我从您的代码片段中看到的那样,当前的内存策略是“传递所有权”。例如。你创建3个point实例,然后将它们传递给Frame构造函数 - 从这一刻起,Frame实例负责管理那3点内存。因此,这意味着您必须为Frame类提供析构函数,该类将负责存储为成员的3个点中的每个点的内存删除。
以上所有内容都是关于“原始记忆”tecnique,这不是新星天。请改用智能指针。例如,std :: auto_ptr在这里是一个不错的候选者(但要注意一些陷阱:如果将一个auto_ptr复制到另一个,则源将被清除为NULL,目标将拥有内存)。另一个广泛传播的候选者是boost :: shared_ptr(它甚至包含在最新的C ++标准中作为tr1 :: namespace的一部分)。并且不要忘记:您必须了解用于您选择的智能指针的内存策略。否则,你最终会与被破坏的实体的鬼魂交谈,或者你的实例将永远不会像瓶子里的精灵那样被释放。
答案 5 :(得分:1)
这很大程度上取决于惯例。这看起来像是一部分
一个GUI,GUI中的通常的约定就是
包含对象一旦负责delete
已经传递了指针。因此,Animation
会delete
析构函数中frameList
中的所有指针,以及
Frame
将删除它在析构函数中保存的任何指针。
(请注意,此约定对于GUI非常特殊,但是,
在大多数其他情况下,其他公约将是
使用。)
话虽如此,它在C ++中的价值也非常不典型
像Point
一样动态分配开始,和
也没有指向它们的指针。
答案 6 :(得分:-1)
class X {
public:
// Constructor for class X
X();
// Destructor for class X
~X();
};
在X对象删除时自动调用X :: ~X()。
如果我错了,请纠正我。