在C ++中,处理内存分配/删除的任何一般准则?

时间:2010-07-20 12:09:55

标签: c++ memory memory-management pointers

我要求的所有内容都可能是指向我尚未找到的网站的链接。但是来自Java背景,在C ++中处理内存分配和删除的一般原则是什么?我觉得我可能会在我的应用程序中添加各种内存泄漏。我意识到有几种智能指针的变种,你也可以提到我,但我想关注标准的C ++指针。

9 个答案:

答案 0 :(得分:17)

我通常的政策就是这个

  • 使用智能指针,其中使用情况非常复杂。
  • 所有原始指针都由负责删除它的特定对象拥有。
  • 如果要稍后设置,构造函数总是分配指针或将其初始化为null。
  • 析构函数总是删除任何包含的指针
  • 这些规则确保删除指针时删除其拥有的对象,从而消除最常见的内存泄漏情况。
  • 永远不要将内部指针传递到另一个对象,始终传递容器对象,并让容器对象的被调用函数调用成员函数作用于“指针”。
  • 禁用复制容器对象。在极少数情况下,实现副本以便复制指向的对象。但是,永远不要在没有复制包含对象的情况下复制拥有对象。
  • 前两条规则确保您不能拥有指向已删除内存的指针副本。
  • 不要尝试实现引用计数。如果需要引用计数指针,请使用智能指针类并包含它。

我发现这些规则通常可以确保您可以安全有效地使用原始指针,如果您想破坏这些规则,那么请使用智能指针。

答案 1 :(得分:5)

通常,我们使用new来分配内存,使用delete来释放内存。 (主要是因为new调用了适当的构造函数,而delete调用了适当的析构函数。)

但是大多数人会建议你不要使用原始指针而不是用于教育目的(除非智能指针的开销很大,比如嵌入式编程)。

了解工作是很重要的,但在大多数情况下,您可以利用设计良好的智能指针类来使您更轻松(并且通常更安全)。

智能指针存在的原因是:帮助程序员完成优秀的程序,而不必关心太多处理分配/解除分配。

答案 2 :(得分:5)

使用极端偏执的指针。对于在类中声明的每个成员变量,记录它是否拥有它指向的内存的内存生存期。如果是,那么它负责分配和释放内存。如果它确实拥有它指向的内存,请将其清楚地记录下来! 还记得,在构造函数中分配并在析构函数中释放。这是一个很好的规则,你忽略了你的危险。 除了你使用它们之外,你的指针也是空的。初始化时将它们清空,然后释放它们。 在解除引用它们之前,将大量断言放在检查指针完整性的地方。 放入真正的警卫来处理他们不好的情况。

最后也是最重要的:

点燃贵公司任何滥用这些政策的bozo !!!它们确实会给您的产品注入无法估量的伤害,并在路上造成大量的虫子和头痛。

编辑: link Favorite c++ website

答案 3 :(得分:4)

我也来自Java,花了一些时间来了解C ++中的优秀设计。起初,很难想象删除事物的责任是谁。答案是将这些职责推迟到对象,让对象拥有/管理其他对象或资源,让他们担心删除/释放或复制。 C ++使构造函数,析构函数等变得容易。它们的关键字是“RAII”(资源获取是初始化)。

通常,我设法将“x拥有y” - 关系组织为一个森林,其中树的根存在于堆栈(自动存储器)中。通过使用标准容器并避免指针作为数据成员,我将代码中的新/删除调用的数量减少到最少(几乎没有)。这是最简单的方法。有时,您可能觉得需要使用共享所有权智能指针,但根据我的经验,人们倾向于过度使用这些指针。但它们在某些情况下当然有用。

答案 4 :(得分:4)

将每个new(或new[])与delete(或delete[])配对。

RAII是你的朋友。开发在构造函数中获取资源的类,并在析构函数中释放它们。

答案 5 :(得分:1)

如果你确实需要处理原始指针,那么我建议如果可能的话用智能指针包装它们。如果您要将它们存储在STL容器中,则需要使用tr1::shared_ptr而不是auto_ptr

在你学习的过程中,我建议你尽可能避免指点,以避免头痛。例如,如果你想要一个int的数组,你可以使用vector而不是自己分配和释放内存。如果要实例化一个类,请在自动存储器中进行,即

MyClass myObject;

而不是

MyClass *myObject = new MyClass();
// ...
delete myObject;

答案 6 :(得分:1)

我使用以下政策:

  • 永远不要使用拥有对象的原始指针。

    Foo *f=new Foo(); // Bad!
    

    即使在课程中:

    class Bar {
         Bar(Bar const &); // non copyable
         void operator=(Bar const &);
    public:
          Bar() {
              f1_=new Foo();
              f2_=new Foo(); // this throws then f1_ never destroyed!
          }
          ~Bar() { delete f1_; delete f2_ ;} 
          Foo *f1_,*f2_;
    };
    // Bad code
    

    正确:

    class Bar {
         Bar(Bar const &); // non copyable
         void operator=(Bar const &);
    public:
          Bar() {
              f1_.reset(new Foo())
              f2_.reset(new Foo());
          }
          std::auto_ptr<Foo> f1_,f2_;
    };
    // Good code
    
  • 对于没有共享所有权的对象,请使用auto_ptr

    std::auto_ptr<Foo> f(new Foo()); // Good
    
  • 对于共享所有权或容器,请使用boost::shared_ptrstd::tr1::shared_ptr

    std::vector<boost::shared_ptr<Foo> > foos;
    
  • 当我需要将对象的所有权转移给其他对象时,请使用auto_ptr

    void assign_foo(std::auto_ptr<Foo> f)
    {
       /// I own foo
    }
    
    std::auto_ptr<Foo> transfer_foo(std::auto_ptr<Foo> f) { ... } 
    // Now foo is owned by caller
    

    所以很清楚谁给谁一个指针。

  • 原始指针仅允许作为可以为null的引用 从不拥有对象

    void bar1(Foo *f) { do something with f if f!=NULL}
    

答案 7 :(得分:0)

您是否考虑过使用垃圾收集器?这个Garbage Collector目前被Mono项目使用,虽然我知道它会被更积极的版本所取代。它可能会有所帮助,因为它将在使用C / C ++进行开发时提供类似的体验,就像您在Java上开发一样。

答案 8 :(得分:0)

正如其他人所说,你需要阅读RAII。我发现this在我学习C ++时非常有用,它已经很老了,但却提供了基本的想法。