C++ 如果内存不足,则释放指针';不要被其他任何东西引用

C++ 如果内存不足,则释放指针';不要被其他任何东西引用,c++,C++,我有一个方法,它有几个指针作为参数。可以使用被调用方的命名指针调用此方法,也可以动态创建指向新对象的指针,并在调用方法时直接将其作为参数传入 myClass *myPtr = new myClass(...); myMethod(myPtr); 维鲁斯 问题是,如果这两个选项都有效,如何正确释放传入的指针?如果在程序中再次访问myPtr,则在myMethod中删除myPtr将导致崩溃。如果我不删除myPtr,第二个选项在使用时会导致内存泄漏。使用这两个选项都有好处,因此两者都不应破坏程序 除了

我有一个方法,它有几个指针作为参数。可以使用被调用方的命名指针调用此方法,也可以动态创建指向新对象的指针,并在调用方法时直接将其作为参数传入

myClass *myPtr = new myClass(...);
myMethod(myPtr);
维鲁斯

问题是,如果这两个选项都有效,如何正确释放传入的指针?如果在程序中再次访问myPtr,则在myMethod中删除myPtr将导致崩溃。如果我不删除myPtr,第二个选项在使用时会导致内存泄漏。使用这两个选项都有好处,因此两者都不应破坏程序


除了使用STL,还有哪些解决方案?我必须实现自己的垃圾收集器吗?

您可以使用智能指针,比如boost

如果没有,您需要明确说明对象的所有者。如果您打算接管所有权或将其留给来电者。
如果将它留给调用者,那么使用form
函数(newwhere())
不是一个好主意,但是泄漏将由调用者负责


如果您打算接管所有权,创建一个sink方法,选择一个合适的名称将是一个好主意,当然您需要在完成后自己删除对象。

首先,您需要分配对象的所有权:您需要对“谁”有一个一致的策略(并强制执行!)有权删除对象。一旦明确了这一点,你就不应该有你遇到的问题

一些战略:

  • 租赁对象:所有权由贷款人保留

  • 对象已给定:所有权已转移

  • 其次,为了跟踪对象的使用情况,您需要一个诸如“智能指针”之类的基础设施。这里有两个类别需要关注:

  • 对象是“单独引用的”,即只有一个“用户”

  • 对象是“多引用的”,即在一个时间点有多个“用户”

  • 对于(1),“跟踪信息”是指针本身,而在(2)中,您需要更多的基础设施

    我想说,在这种情况下,调用方应该负责释放对象。你可以考虑各种选项,最简单的是:

    myClass myInstance = myClass;  // or myClass(arg1, arg2, ...)
    // and the pass it to your method like this:
    myMethod(&myInstance);
    

    您还可以考虑一些智能指针选项,例如“代码> STD::Tr1::SysDypPTR 或来自Boosi.

    的某些内容。 更新:如果您的方法应该能够获取
    NULL
    -指针作为其参数,那么根本没有问题:

    // this is your method declaration:
    void myMethod(const myClass *myPtr);
    
    // in your tests or wherever in your code you can call it like
    myClass myInstance = myClass;  // or myClass(arg1, arg2, ...)
    myMethod(&myInstance);
    // or like this:
    myMethod(NULL);
    // for as long as your method has something like this in it:
    if (myPtr)
        myPtr->someMethod();
    

    您应该使用某种智能指针。
    对于这种简单的情况,任何
    自动\u ptr
    都可以,但一般来说,您应该使用
    范围\u ptr
    共享\u ptr


    如果您对STL或boost有一些无法解释的恐惧,您可以相对轻松地拉取自己的智能指针类(如果您不需要超级异常安全)。

    这是一个关于所有权的问题

    您需要决定谁拥有所有权(或是否存在共享所有权)。
    基本上传递指针是一个非常糟糕的想法,并且<>强>不<强>非常类似C++(这基本上是一个C接口,因为没有所有权的概念)。在C++程序中,你应该定义一个非常清楚的所有权转移的接口(函数)。 你有两个选择

  • 该函数没有所有权,不能为空。
    在这种情况下,您应该通过引用传递
  • 该函数没有所有权,但可能为空。
    作为指针传递,并添加所有权未转移的注释。这是最糟糕的情况,您应该尽量避免这种情况,因为代码没有清楚地表达语义
  • 该功能拥有所有权。
    在这种情况下,我建议使用std::auto_ptr,因为它明确表示所有权正在转移到函数
  • 该功能共享所有权。
    在这种情况下,某种形式的共享智能指针,如boost::shared_ptr或std::tr1::shared_ptr
  • 在您的情况下,我会根据情况建议1或2。

    显然,函数不能删除指针,因为它有时可能没有所有权。因此,所有权仍然属于调用方。因此,调用方必须根据需要调用delete。希望通过一些智能指针机制。

    您需要决定所有权,或者:

  • 调用者拥有对象:对象被借给函数,调用者负责分配和删除

  • 函数拥有对象:对象被捐赠给函数,调用者负责分配,被调用者(函数)负责删除

  • 通过共享指针使用引用计数可避免此问题


  • (2是丑陋的,因为它意味着不同的代码负责分配和删除,但对于您的情况,这可能是正确的解决方案-如果调用方希望保留对象,它还意味着复制参数)

    > P >这两种都是C++语法意义上的有效选项,但我认为第二种选择是几乎所有的软件设计都是糟糕的,并且允许一个函数中的两个选项甚至在所有情况下都是坏的软件设计。 调用类创建对象、调用方法并删除对象,
    调用类创建对象,调用methon,并期望该方法删除该对象


    我看不出在一个方法调用中两个选项都是合理的。从文档或注释中应该清楚该方法使用的是哪个版本,然后由开发人员使用该方法,否则后果自负

    函数的常见行为是既不创建也不销毁对象。但是,有些函数确实可以。常见的行话是“源和汇”。如果可以的话,这是一个非常有用的约定
    // this is your method declaration:
    void myMethod(const myClass *myPtr);
    
    // in your tests or wherever in your code you can call it like
    myClass myInstance = myClass;  // or myClass(arg1, arg2, ...)
    myMethod(&myInstance);
    // or like this:
    myMethod(NULL);
    // for as long as your method has something like this in it:
    if (myPtr)
        myPtr->someMethod();
    
    void foo() {
      myClass* p = new myClass(); // foo owns the pointer, so foo should release it again
    }
    
    void foo() {
      boost::shared_ptr<myClass> p = new myClass(); // foo allocates the memory, but *transfers* ownership to the smart pointer. The smart pointer is now responsible for freeing the object. (This is true for all types of smart pointers, including boost::scoped_ptr, std::auto_ptr or the C++0x std::unique_ptr.
    }
    
    void foo() {
      ScopedMyClass x; // ScopedMyClass is some class wrapper which *internally* calls `new myClass`, and so owns the allocation and is responsible for freeing it before the end of the wrapper class' lifetime.
    }
    
    myMethod(new myClass(...));
    
    myClass* p = new myClass(...);
    myMethod(p);
    delete p;
    
    myMethod(myClass(...));
    
    myMethod(new myClass(...));
    
    myMethod(myClass& a) { return myMethod(&a); }
    
    myMethod(myClass(...))
    
    // Value
    void method(T);
    
    // Reference
    void method(T&);
    
    // Pointer
    void method(T*);
    
    // Smart Pointer
    void method(std::auto_ptr<T>);
    
    void method(T*); // do something
    
    void method(std::auto_ptr<T> p)
    {
      method(p.get());
    }
    
    void method(T&); // do something
    void method(T* p)
    {
      if (p) method(*p); else throw NullPointer("method");
    }