C++:由于函数返回的类引用,构造函数和析构函数不成对出现

Jac*_*ack 0 c++

众所周知,构造函数和析构函数成对出现.

但是下面的代码不是这样的,构造函数被调用两次但是析构函数只被调用一次!

{
    Animal ahe;
    ahe = CreateAnimal();
}
Run Code Online (Sandbox Code Playgroud)

请继续阅读以获得更详细的解释.

假设有一个名为Animal的类,我们有以下代码:

int main(int argc, char* argv[])
{
    Animal ahe;

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

预计Animal的构造函数和析构函数都将被调用一次且仅被调用一次.当我运行代码时,它的行为完全符合我的预期.

但是当涉及到一个函数返回Animal的引用时,它看起来很奇怪.当我运行代码时,构造函数被调用两次,但析构函数只被调用一次!

#include "stdafx.h"
#include "stdio.h"
#include "iostream.h"

class Animal
{
public:
    Animal();
    Animal(long age);

    ~Animal();
private:
    long m_age;
};

Animal::~Animal()
{
    cout<<"Animal::~Animal()"<<"age="<<m_age<<endl;
}
Animal::Animal()
{
    m_age = 1;
    cout<<"Animal::Animal()"<<"age="<<m_age<<endl;
}

Animal::Animal(long age)
{
    m_age = age;
    cout<<"Animal::Animal()"<<"age="<<m_age<<endl;
}

Animal& CreateAnimal()
{
    Animal *pAnimal = new Animal(5);

    return *pAnimal;
}

int main(int argc, char* argv[])
{
    Animal ahe;

    ahe = CreateAnimal();

    return 0;
}
Run Code Online (Sandbox Code Playgroud)

//输出

Animal::Animal()age=1
Animal::Animal()age=5
Animal::~Animal()age=5
Run Code Online (Sandbox Code Playgroud)

显然,没有调用第一个对象的析构函数,为什么?如果Animal有很多需要在析构函数中释放的资源,问题可能会很严重.

Sid*_*Sid 6

您正在通过new在CreateAnimal中创建对象,它将调用构造函数,但您需要显式调用析构函数以获取通过new创建的对象.代码实际上正如预期的那样工作.为两个对象调用构造函数,但是当第一个对象超出范围时,它会在堆栈上调用析构函数,但使用new创建的析构函数永远不会被删除.您需要在其上显式调用delete.

它是调用析构函数的那个​​对象的副本.当你指定ahe = CreateAnimal(); 在堆栈上创建副本,因为它不是引用

   Animal ahe; // -> constructor called for object on stack
     ahe = CreateAnimal();  // -> constructor called due to new call and ahe created in previous //line replaced with the object created via new
     } // main method ends, ahe goes out of scope and it's destructor is called but since  //it now contains a copy of the object created via new, it prints 5
Run Code Online (Sandbox Code Playgroud)

如果您不想记住为使用new创建的每个对象调用delete,则只需使用auto_ptrs.

  • 可能值得一提的是智能指针或移动语义以及我们应该永远不会返回对函数内免费存储分配的对象的引用.这甚至比返回一个期望客户端删除的指针更糟糕,因为它将是一个更加隐藏的内存泄漏,如果不改变整个界面就无法修复. (2认同)