什么是删除我的指针?

时间:2013-09-25 13:07:22

标签: c++ memory-management scope

我经常想知道,

我知道我可以使用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是一种非托管结构,因此在托管代码中使用时,必须由我自己(程序员)管理。 :)

7 个答案:

答案 0 :(得分:11)

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

在上面的实际案例中,Frame对象本身必须负责delete传入的3个指针,并且构造Frame本身必须负责{{1}那个。

由于资源所有权是一个雷区,程序员很久以前发明了许多技术来澄清所有权的语义,并使粗略的程序员引入错误和泄漏变得更加困难。现在,在C ++中,它被认为是避免原始指针的最佳实践,事实上,只要有可能,就会完全动态分配 - 主要是因为资源所有权是一个非常危险的雷区。

在C ++中,用于实现这些目标的主要习惯是RAII,使用的主要工具是delete(C ++ 03),auto_ptrunique_ptr及其同类。 Boost还提供了许多所谓的“智能指针”。其中许多与C ++ 11中发现的并行(事实上,C ++ 11中的新智能指针最初是由Boost开发的),但也有一些超越了,例如shared_ptr

答案 1 :(得分:2)

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

完成后,您的问题的答案是Animation需要释放frameList中的所有内容,而Frame需要释放传入的point* shared_ptr 1}}秒。不会删除原始指针。

更好的答案(虽然不是你要求的)是你应该使用unique_ptrframeList来管理内存 - 这些将删除指向对象。这绝对是我为std::vector<std::shared_ptr<Frame>>所做的 - 让它成为point

在这种情况下,可能没有充分的理由使用{{1}}的指针(我猜它们只是坐标,并且复制起来非常便宜) - 我只是按值传递它们或const引用。这样就没有涉及堆分配,而且更加简单。

答案 2 :(得分:1)

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

答案 3 :(得分:1)

如果您正在调用的函数没有明确说明它将在完成时获取传递指针delete的所有权,那么您自己deletenew任何事情负责。

答案 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 已经传递了指针。因此,Animationdelete 析构函数中frameList中的所有指针,以及 Frame将删除它在析构函数中保存的任何指针。 (请注意,此约定对于GUI非常特殊,但是, 在大多数其他情况下,其他公约将是 使用。)

话虽如此,它在C ++中的价值也非常不典型 像Point一样动态分配开始,和 也没有指向它们的指针。

答案 6 :(得分:-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()。

如果我错了,请纠正我。