C++ 如何确保在编写C++;代码本身是否不会导致任何内存泄漏?

C++ 如何确保在编写C++;代码本身是否不会导致任何内存泄漏?,c++,memory-leaks,C++,Memory Leaks,接下来的步骤是运行valgrind或purify 但是,在编写代码时,如何确保它不会导致任何内存泄漏? 您可以确保以下事项:- 1:要删除的新文件数 2:打开的文件描述符是否关闭 还有别的吗?在任何地方都可以使用这个成语 在适当的情况下使用智能指针,例如std::auto_ptr。(不要在任何标准集合中使用auto_prt,因为它不会像您认为的那样工作)确保应用程序创建的共享内存被释放,如果没有人再使用它,请清理内存映射文件 基本上,确保清理应用程序直接或间接创建的任何类型的资源。文件描述符只是

接下来的步骤是运行valgrind或purify 但是,在编写代码时,如何确保它不会导致任何内存泄漏? 您可以确保以下事项:- 1:要删除的新文件数 2:打开的文件描述符是否关闭

还有别的吗?

在任何地方都可以使用这个成语


在适当的情况下使用智能指针,例如std::auto_ptr。(不要在任何标准集合中使用auto_prt,因为它不会像您认为的那样工作)

确保应用程序创建的共享内存被释放,如果没有人再使用它,请清理内存映射文件


基本上,确保清理应用程序直接或间接创建的任何类型的资源。文件描述符只是应用程序在运行时可能使用的一种资源。

当我需要在堆上创建新对象时,我总是使用
std::auto_ptr

std::auto_ptr<Foo> CreateFoo()
{
   return std::auto_ptr<Foo>(new Foo());
}

如果在代码中为数据结构递归生成任何树或图形,它将不会泄漏。

可能会占用所有内存。

尽可能避免动态创建对象。来自Java和其他类似语言的程序员通常编写以下内容:

string * s = new string( "hello world" );
他们应该在什么时候写:

string s = "hello world";
类似地,它们在应该创建值集合时创建指针集合。例如,如果您有这样一个类:

class Person {
   public:
      Person( const string & name ) : mName( name ) {}
      ...
   private:
      string mName;
};
而不是像这样编写代码:

vector <Person *> vp;

人和向量的所有内存都是为你管理的。当然,如果您需要一组多态类型,您应该使用(智能)指针

可以使用静态代码分析工具来完成这类工作;这是一个开始寻找的好地方。基本上,除了小心选择正确的容器外,您无法保证您编写的代码,因此需要valgrind和gdb等工具。

通过使用STL容器存储数据来最小化对new的调用。

基本步骤有两个:

首先,要知道每一个新项目都需要删除。因此,当您使用新操作符时,请提高您对该对象将要执行的操作、如何使用它以及如何管理其生命周期的认识

第二,确保永远不要覆盖指针。您可以使用智能指针类而不是原始指针来实现这一点,但如果您确实这样做了,请确保您永远不会将其用于隐式转换。(例如:使用MSXML库,我创建了一个用于保存节点的CCOMPtr智能指针,以获取一个调用get_node方法的节点,并传入智能指针的地址,该智能指针具有一个返回底层指针类型的转换运算符。不幸的是,这意味着如果智能指针已经保存了数据,则该成员数据将结束。)已写入,正在泄漏上一个节点)

我认为这两种情况下,你可能会泄漏内存。如果您只直接使用智能指针,而不允许暴露其内部数据,则可以避免后一个问题。如果您将所有使用new和delete的代码包装在一个类中(即使用RAII),那么与前者相比,您也非常安全

避免C++中的内存泄漏非常容易,如果你做到了。

  • 使用RAII
  • 隐藏默认复制因子,运算符=() 每节课,, 除非a)你的课程很琐碎 只使用本机类型,您知道 你永远都是这样 明确定义自己的
  • 在1)RAII上,想法是让删除自动发生,如果你发现自己在想“我刚打电话给new,我需要记住在某处打电话给delete”,那么你就做错了。删除应该是a)自动的,或者b)放入dtor(哪个dtor应该是明显的)


    2)隐藏默认值。识别恶意的默认拷贝复制者等可能是一场噩梦,最简单的事情是通过隐藏它们来避免它们。如果您有一个通用的“根”对象,所有内容都从该对象继承(对于调试/分析来说很方便),那么在这里隐藏默认值,那么当某个东西试图分配/复制继承类时,编译器会发出barfs,因为在基类上无法使用ctor的etc。

    两个简单的经验法则:

    • 永远不要显式调用
      delete
      (即,在RAII类之外)。每个内存分配都应该由在析构函数中调用delete的类负责
    • 几乎从不显式调用
      new
      。如果您这样做了,您应该立即将结果指针包装在智能指针中,智能指针将获得分配的所有权,并如上所述工作
    在您自己的RAII类中,两个常见的陷阱是:

    • 未能正确处理复制:如果复制对象,谁拥有内存?他们是否创建了新的分配?您是否同时实现复制构造函数和赋值运算符?后者处理自我分配吗
    • 不考虑异常安全。如果在操作过程中引发异常(例如,赋值),会发生什么情况?对象是否恢复为一致状态?(无论发生什么情况,它都应该这样做)它是否会回滚到操作前的状态?(如果可能的话,它应该这样做)
      std::vector
      必须处理这个问题,例如在
      push_back
      期间。这可能会导致向量调整大小,这意味着1)内存分配可能抛出,2)必须复制所有现有元素,每个元素都可能抛出。像
      std::sort
      这样的算法也必须处理它。它必须调用一个用户提供的比较器,它可能也会抛出!如果发生这种情况,序列是否处于有效状态?临时对象是否被彻底销毁
    如果您在RAII类中处理上述两种情况,它们几乎不可能泄漏内存。 如果使用RAII类包装所有资源分配(内存分配、文件句柄、数据库)
    vector <Person *> vp;
    
    vector <shared_ptr <Person> > vp;
    
    vector <Person> vp;
    
    vp.push_back( Person( "neil butterworth" ) );