繁体   English   中英

对象何时在 C++ 中真正被销毁? delete(ptr) 有什么作用?

[英]When Does Object Actually Gets Destroyed in C++? What does delete(ptr) Do?

没有delete的程序完美运行。 但是,在使用delete ,我没有得到任何结果。 该计划突然终止。

#include<iostream>
using namespace std;

class Book
{
  string *title;
  int *price,*stock;

public:
  Book()
  {
    title=new string();
    price=new int();
    stock=new int();
  }

  Book(string n,int p,int s)
  {    
     title=new string(n);
     price=new int(p);
     stock=new int(s);
  }

  ~Book()
  {
     cout<<"Object Destroyed"<<endl;
     // delete (title);  Using Delete i am getting Wrong Results.
     // delete (price);
     // delete (stock);
  }

  void inst();
  void buy();
  void display();
};

void Book::display()
{
  cout<<"Title :"<<*title;
  cout<<" Price is :"<<*price;
  cout<<" Stock is :"<<*stock;
  cout<<endl;
}

int main()
{
  Book a[2];

  for(int x=0;x<2;x++)
  {
    string title;
    int p,s;
    cout<<"Enter title,price,stock respectively"<<endl;
    cin>>title;
    cin>>p;
    cin>>s;
    a[x]=Book(title,p,s);
  }

  for(int x=0;x<2;x++)
    a[x].display();
}

以下是输出:

Enter title,price,stock respectively
C++
120
2
Object Destroyed
Enter title,price,stock respectively
JAVA
150
5
Object Destroyed
Title :C++   Price is :120    Stock is :2
Title :JAVA  Price is :150    Stock is :5
Object Destroyed
Object Destroyed

为什么每次输入后Object Destroyed都会被Object Destroyed

Book不遵循3/5/0 规则

你有一个默认构造函数和一个转换构造函数来分配内存,还有一个析构函数来释放内存,但你没有复制构造函数或复制赋值运算符(或移动构造函数或移动赋值运算符)。 因此,编译器将提供隐式实现,将指针原样从一个对象浅拷贝到另一个对象,而不是对所指向的数据进行深拷贝。

这个说法:

Book a[2];

默认构造 2 个Book对象,并为每个对象分配数据。

这个说法:

a[x]=Book(title,p,s);

为用户的输入构造一个临时Book对象,然后将该临时对象复制分配给数组中的现有对象,最后销毁临时对象,释放它所指向的内存。

编译器生成的复制赋值运算符将指针浅拷贝到另一个对象(泄漏它已经指向的内存),因此当临时释放内存时,分配给对象中的指针悬空。 display()尝试访问无效内存时,您的代码会崩溃。

试试这个:

#include <iostream>
#include <algorithm>
using namespace std;

class Book
{
  string *title;
  int *price, *stock;

public:
  Book() :
    title(new string()),
    price(new int()),
    stock(new int())
  {
  }

  Book(const Book &src) :
    title(new string(*src.title)),
    price(new int(*src.price)),
    stock(new int(*src.stock))
  {
  }

  // C++11 and later only...
  Book(Book &&src) :
    title(nullptr),
    price(nullptr),
    stock(nullptr)
  {
    swap(title, src.title);
    swap(price, src.price);
    swap(stock, src.stock);
  }

  Book(string n, int p, int s) :
    title(new string(n)),
    price(new int(p)),
    stock(new int(s))
  {    
  }

  ~Book()
  {
     delete title;
     delete price;
     delete stock;
  }

  Book& operator=(const Book &rhs)
  {
    if (&rhs != this)
    {
      Book tmp(rhs);
      swap(title, tmp.title);
      swap(price, tmp.price);
      swap(stock, tmp.stock);
    }
    return *this;
  }

  // C++11 and later only...
  Book& operator=(Book &&rhs)
  {
    swap(title, rhs.title);
    swap(price, rhs.price);
    swap(stock, rhs.stock);
    return *this;
  }

  ...

  void display();
};

void Book::display()
{
  cout << "Title :" << *title;
  cout << " Price is :" << *price;
  cout << " Stock is :" << *stock;
  cout << endl;
}

更简单的解决方案是争取零规则——编写不需要自定义复制/移动构造函数、复制/移动运算符或析构函数的代码。 让编译器生成的实现为您完成所有必要的工作:

#include <iostream>
using namespace std;

class Book
{
  string title;
  int price, stock;

public:
  Book() :
    title(), price(0), stock(0)
  {
  }

  Book(string n, int p, int s) :
    title(n), price(p), stock(s)
  {    
  }

  ...

  void display();
};

void Book::display()
{
  cout << "Title :" << title;
  cout << " Price is :" << price;
  cout << " Stock is :" << stock;
  cout << endl;
}

a[x]=Book(title,p,s)程序执行两个步骤:

  1. 使用构造函数创建 Book 实例。 让我们称这个实例为“alpha”
  2. 使用复制构造函数创建 Book (a[x]) 的新实例。 让我们称这个实例为“beta”

当到达 for 括号的末尾时,“alpha”的生命线结束并调用析构函数。

还记得复制构造函数吗? 使用它复制指针。 不会创建成员变量的新实例。 讨厌删除部分,那些成员变量在“alpha”的生命线结束时被删除,并调用相应的析构函数。 尝试访问仍由“beta”指针引用的已删除变量会导致崩溃。

正如评论中所强调的,有多种解决方案可以解决该问题:

  1. 不要使用指针
  2. 实现复制构造函数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM