关于构造函数和内存泄漏的问题

Question about constructors & memory leak

我正在测试构造函数和析构函数,我想看看我是否可以将对象传递给函数而不先声明它,就像这个例子:

#include<iostream>
#include<stdlib.h>
using namespace std;

class car
{
public:
    string name;
    int num;

public:
    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(car* p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    display(new car("HYUNDAI", 2012));
}

display 函数运行良好,完全符合我的预期,但我想知道:

Would that new cause a memory leak?

是的,它导致了内存泄漏。无论你 newed 应该 deleteed 之后 wards(手动内存管理)。


why didn't my user-defined destructor get called?

因为对象还没有deleted,因此没有被破坏。

你应该做的

void display(car* p)
{
    if (p) // check p is valid pointer
    {
        std::cout << "Name: " << p->name << std::endl;
        std::cout << "Num: " << p->num << std::endl;
        // ...after use
        delete p;
    }
}

除了手动内存管理,您还可以使用智能指针。

What is a smart pointer and when should I use one?


也就是说,对于所示的案例,您不需要指针(除非您想用指针练习)。一种选择是将其作为 const car& 传递,这也适用于临时对象。

void display(const car& p)
//           ^^^^^^^^^^^^
{
    std::cout << "Name: " << p.name << std::endl;
    std::cout << "Num: " << p.num << std::endl;
     
}

你可以将 car 作为

display(car{ "HYUNDAI", 2012 });

参见:What are the differences between a pointer variable and a reference variable in C++?

是的,您的程序中存在内存泄漏,因为每当您使用 new 关键字分配一些内存时,您必须始终使用 delete 在以后不再需要时释放该内存。否则你会像在你的程序中那样发生内存泄漏。有两种方法可以解决您的问题:

解决方案 1:明确使用删除

int main()
{
    car * ptr = new car("HYUNDAI", 2012);
    display(ptr);
    
    //use delete to free up memory 
    delete ptr; //this will call the destructor
}

方案二:使用智能指针

#include<iostream>
#include<stdlib.h>
#include <memory>
using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(std::shared_ptr<car> p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    std::shared_ptr<car> ptr = std::make_shared<car>("HYUNDAI", 2012);
    
    display(ptr);
    
    //there is no memory leak
    //you don't need to use delete explicitly
    
}

使用智能指针(如 shared_ptr 或 unique_ptr)的优点是您不必显式释放内存。

使用 unique_ptr 解决方案 2 看起来像:

#include<iostream>
#include<stdlib.h>
#include <memory>
using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};

void display(const std::unique_ptr<car> &p)
{
    cout << "Name: " << p->name << endl;
    cout << "Num: " << p->num << endl;
}

int main()
{
    unique_ptr<car> p1(new car("HYUNDAI", 2012));
    
    display(p1);
    
    //there is no memory leak
    //you don't need to use delete explicitly
    
}

请注意,在您的情况下,您不需要传递指向 display 的指针。您可以改为直接传递对象,如下所示:

#include<iostream>
#include<stdlib.h>

using namespace std;

class car
{
public:
    string name;
    int num;

public:

    car(string a, int n)
    {
        cout << "Constructor called" << endl;
        this->name = a;
        this->num = n;
    }
    ~car()
    {
        cout << "Deleted" << endl;
    }
};
//note pass by value(other way would be to use pass by reference like const car& p)
void display(car p)
{
    cout << "Name: " << p.name << endl;
    cout << "Num: " << p.num << endl;
}

int main()
{
    
    display(car("HYUNDAI", 2012));
}