【问题标题】:Question about constructors & memory leak关于构造函数和内存泄漏的问题
【发布时间】:2021-12-06 02:01:20
【问题描述】:

我正在使用构造函数和析构函数进行测试,我想看看是否可以在不先声明的情况下将对象传递给函数,例如以下示例:

#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 函数工作正常,它完全符合我的预期,但我想知道:

  • 如果我在display 的输入中声明了new 关键字,为什么我的用户定义的析构函数没有被调用,并且
  • new 会导致内存泄漏吗?

【问题讨论】:

  • 您使用什么资源来学习 C++?在display 中使用new 没有意义,“声明new 关键字”这句话也没有意义。任何体面的书或课程都应该告诉您诸如对象生命周期和指针之类的事情,这将帮助您理解这里的问题以及为什么会出现泄漏。也许您可能需要投资some good books
  • 您将stringint 传递给构造函数,并将car* 传递给display,但没有先声明它们中的任何一个。
  • 考虑使用自动变量并将display() 设为car 成员函数。 example

标签: c++ class constructor memory-leaks destructor


【解决方案1】:

新的会导致内存泄漏吗?

是的,它导致了内存泄漏。不管你newed 应该是deleteed 病房后(手动内存管理)。


为什么我的用户定义的析构函数没有被调用?

因为对象不是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&amp; 传递,这也适用于临时对象。

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++?

【讨论】:

  • 或者根本不使用指针(在这种特定情况下并不真正需要)。
  • @Someprogrammerdude 完全同意。我假设 OP 想要练习指针而不是适当的用法。
  • 我还有一个问题,@JeJo,当您写 car{ "HYUNDAI", 2012 } 时,它实际上是什么意思以及为什么会起作用?
【解决方案2】:

是的,您的程序中存在内存泄漏,因为每当您使用 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
}

解决方案 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(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));
}

【讨论】:

  • 正如@Some Programmer 花花公子所说,根本不需要指针/智能指针。顺便说一句,std::make_shared 不应该是第一个建议,如果你可以unique_ptr 并且没有什么可以算作参​​考。
  • @Const 当然,同一个程序可以用许多不同的方式编写。例如,在这种特殊情况下,OP 可以在 main() 中创建一个 car 类型的对象,然后将该对象(通过引用或他/她选择的值)直接传递给display(),而不是传递指向该对象的指针.我纠正了他/她在使用/传递指针时所犯的错误。
猜你喜欢
  • 2019-08-19
  • 1970-01-01
  • 2021-06-17
  • 2013-01-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多