6

我常常想,

new我知道我可以使用关键字创建指向对象实例的指针,同时将相同的指针作为参数传递给函数。就像我在Animation::newFrame函数下面一样,在下面的示例中给出。

但是,我也知道,作为一般规则,我负责调用delete我使用new.

所以当我像这样调用Frame的构造函数时:

Frame* myFrame
    = new Frame(new point(0,0), new point(100,100), new point(50,20));

new最终释放我在上述函数调用中创建的 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*而不是按值传递(point)。因为point是非托管结构,因此在托管代码中使用时,必须由程序员本人来管理。:)

4

7 回答 7

11

澄清并经常执行资源所有权的语义是程序员的责任。这可能是一件棘手的事情,尤其是在处理原始指针时,在资源所有权尚未考虑任何真正设计考虑的环境中。后者不仅在新手程序员编写的玩具程序中普遍存在,而且在具有数十年经验的人编写的生产系统中也很普遍,他们应该更了解。

在您上面的实际情况中,Frame对象本身必须delete对传入的 3 个指针负责,而无论构造什么,Frame它本身都必须对它负责delete

因为资源所有权就是这样一个雷区,程序员很久以前就发明了许多技术来澄清所有权的语义,并使粗心的程序员更难引入错误和泄漏。如今,在 C++ 中,避免原始指针和实际上尽可能完全动态分配被认为是最佳实践——主要是因为资源所有权是一个危险的雷区。

在 C++ 中,用于实现这些目标的主要惯用语是 RAII,主要使用的工具是auto_ptr(C++03) unique_ptrshared_ptr和它们的同类。Boost 还提供了许多所谓的“智能指针”。其中许多与 C++11 中的类似(事实上,C++11 中的新智能指针最初是由 Boost 开发的),但也有一些超越,例如intrusive_ptr.

于 2013-09-25T13:15:58.873 回答
2

首先,需要修复您的代码以使其编译 - 例如,您可能无法将 a 分配给point*a point(取决于 的实现point)。

完成此操作后,您的问题的答案是Animation需要释放其 中的所有内容frameList,并且Frame需要释放传入的point*s。不会为您删除原始指针。

一个更好的答案(虽然不是你所要求的)是你应该使用shared_ptrunique_ptr管理内存 - 这些将为你删除指向的对象。这绝对是我要做的frameList——把它变成一个std::vector<std::shared_ptr<Frame>>.

在这种情况下,可能没有充分的理由为points 使用指针(我猜它们只是坐标,并且复制起来非常便宜) - 我只是通过值或 const 引用传递它们。这样就不会涉及堆分配,而且要简单得多。

于 2013-09-25T13:15:49.677 回答
1

如果您正在调用的函数没有明确声明它将delete在完成后获得传递的指针的所有权,那么您对自己的delete任何事情都new负有责任。

于 2013-09-25T13:16:45.050 回答
1

这在很大程度上取决于约定。这看起来像是 GUI 的一部分,并且 GUI 中的通常delete约定是,一旦它被传递了指针,包含的对象就会对它负责。因此,它的析构函数 中的所有指针Animation都会被删除,并且 会删除它在其析构函数中保存的任何指针。(但请注意,此约定对 GUI 非常特殊,并且在大多数其他情况下,将使用其他约定。)deleteframeListFrame

话虽如此,在 C++ 中,对于像动态分配的值一样Point开始分配的值也是非常不典型的,并且也不会有指向它们的指针。

于 2013-09-25T13:35:45.043 回答
1

垃圾收集器,智能指针,有时它是自动的(如果您从堆栈中分配)。基本上,是你负责,但你可以将责任委托给其他地方。

于 2013-09-25T13:12:43.483 回答
1

正如我从您的代码片段中看到的那样,当前的内存策略是“传递所有权”。例如,您创建 3 个点实例,然后将它们传递给 Frame 构造函数——从此刻开始,Frame 实例负责管理这 3 个点的内存。因此,这意味着您必须为 Frame 类提供一个析构函数,该析构函数将负责删除作为成员存储的 3 个点中的每一个的内存。

以上都是关于“原始记忆”技术的,这在新星时代是不必要的。请改用智能指针。例如,std::auto_ptr 在这里是一个不错的候选对象(但要注意一些陷阱:如果将一个 auto_ptr 复制到另一个,源将被清除为 NULL,目标将拥有内存)。这里另一个广泛使用的候选者是 boost::shared_ptr(它甚至包含在最新的 C++ 标准中,作为 tr1:: 命名空间的一部分)。并且不要忘记:您必须了解针对您选择的智能指针的内存策略。否则,您最终将与被破坏实例的幽灵交谈,或者您的实例将永远不会像瓶子里的精灵一样被释放。

于 2013-09-25T13:21:45.827 回答
-1

抱歉,没有完整阅读。你有责任删除你刚刚创建的对象,如果你没有对点的引用,你应该在你的框架对象中创建一个析构函数。 http://publib.boulder.ibm.com/infocenter/lnxpcomp/v8v101/index.jsp?topic=%2Fcom.ibm.xlcpp8l.doc%2Flanguage%2Fref%2Fcplr380.htm

    class X {
    public:
      // Constructor for class X
      X();
      // Destructor for class X
      ~X();
    };

X::~X() 在 X 对象删除时自动调用。

如果我错了,请纠正我。

于 2013-09-25T13:12:08.540 回答