为什么这里没有内存泄漏

Why is there no memory leak here

本文关键字:内存 泄漏 这里 为什么      更新时间:2023-10-16

我试图回答这个问题,所以我决定创建以下简单的测试用例,以便OP可以自己看到内存泄漏。

#include<iostream>
class MyObject
{
public:
   MyObject(){std::cout << "creation of my object" << std::endl;}
   virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo)
{
}
int main()
{
   processMyObject(*new MyObject());
   return 0;
}

我编译了它:

g++ test.cpp -o test

然后,我看到一个意想不到的输出:

creation of my object
destruction of my object

我完全不知道这里发生了什么。谁能给我解释一下?

PS:我使用了g++ 4.6.3

由于按值将对象传递给函数,因此会引发复制或移动复制构造。但是您没有使用原始内存泄漏检查器来跟踪它。你可以提供你自己的复制构造函数,然后你会看到两个对象被创建,只有一个对象被销毁:

#include<iostream>
class MyObject
{
public:
  MyObject() {std::cout << "creation of my object" << std::endl;}
  MyObject(const MyObject&) {std::cout << "copy creation of my object" << std::endl;}
  ~MyObject() {std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject foo) {}
int main() 
{
  processMyObject(*new MyObject());
}
输出:

creation of my object
copy creation of my object
destruction of my object

因为你取的是MyObject的值

因此有一个销毁。但它是在processMyObject的末尾销毁foo参数。

在这种情况下,*new实际上仍然泄漏。

EDIT:正如juanchopanza指出的,您还需要在复制构造函数和移动构造函数中打印语句。

你的代码中发生了什么

  • 您构建一个对象并获取有关它的信息(creation of my object)
  • 传递给函数复制构造函数,但不报告任何内容
  • 副本被销毁-您获得有关它的信息(destruction of my object)
  • 原始实例泄漏,尽管事实上,你没有任何关于它的信息。

怎么看?

在建造和破坏过程中简单地报告指针给this(快速而肮脏,请不要抱怨):

class MyObject
{
public:
   MyObject(){std::cout << "creation of my object (" << (int)this << ")" << std::endl;}
   virtual ~MyObject(){std::cout << "destruction of my object (" << (int)this << ")" << std::endl;}
};
结果:

creation of my object (165437448)
destruction of my object (-1076708692)

如你所见,销毁的对象不同于创建的对象。

如何"修复"它来显示泄漏?

最简单的方法来"修复"你的代码是通过指针传递对象:

#include<iostream>
class MyObject
{
public:
   MyObject(){std::cout << "creation of my object" << std::endl;}
   virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};
void processMyObject(MyObject * foo)
{
}
int main()
{
   processMyObject(new MyObject());
   return 0;
}

另一个选项是报告复制因子和移动因子:

class MyObject
{
public:
   MyObject(){std::cout << "creation of my object" << std::endl;}
   MyObject(const MyObject & obj) { std::cout << "copy-ctor" << std::endl; }
   MyObject(MyObject && obj) { std::cout << "move-ctor" << std::endl; }
   virtual ~MyObject(){std::cout << "destruction of my object" << std::endl;}
};

实际上存在内存泄漏。仅仅因为您的对象被销毁,并不意味着您删除了通过new获得的资源。您必须显式地使用delete

编辑

下面是结果:

    您正在动态调用默认构造函数,并将其传递给函数调用。打印第一条消息。
  1. 作为函数调用的一部分,对象被传递给processMyObject(),使用复制构造函数在该范围内创建一个新对象,该构造函数已由编译器隐式定义。
  2. 当该对象(在processMyObject()中)超出作用域时,调用它的析构函数,打印第二条消息。

因此,打印第一条消息的实例与打印第二条消息的实例是不同的。

希望能把事情说清楚。