为什么这里没有内存泄漏

时间:2014-07-17 09:39:12

标签: c++ memory-leaks

我试图回答this问题,所以我决定创建以下简单的测试用例,以便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

4 个答案:

答案 0 :(得分:6)

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

#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

答案 1 :(得分:4)

因为你按价值取MyObject

因此存在破坏。但它是foo末尾的processMyObject参数的破坏。

在这种情况下,*new确实仍会泄漏。

编辑:正如juanchopanza所指出的,你还需要在复制构造函数和移动构造函数中打印一个语句。

答案 2 :(得分:3)

您的代码中会发生什么

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

怎么看?

只需在施工和销毁过程中报告指向this的指针(quick'n'dirty,请不要抱怨):

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;
}

另一个选择是报告复制ctors和移动ctors:

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;}
};

答案 3 :(得分:1)

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

修改

所以这里发生了什么:

  1. 您正在调用默认构造函数,并将其传递给函数调用。这将打印第一条消息。
  2. 作为函数调用的一部分,对象将传递给processMyObject(),使用复制构造函数在该作用域中创建一个新对象,该对象已由编译器隐式定义。 / LI>
  3. 当该对象(在processMyObject()中)超出范围时,将调用其析构函数,打印第二条消息。
  4. 因此,打印第一条消息的实例与打印第二条消息的实例不同。

    希望能够解决问题。