你能告诉我这个代码为什么崩溃吗

could you tell me why does this code crash?

本文关键字:为什么 崩溃 代码 告诉我      更新时间:2023-10-16

所以我很好奇以下代码崩溃的原因。将感谢帮助。

#include <iostream>
using namespace std;
class temp
{    
  public:
    temp(int i)
    {
        intPtr = new int(i);
    }
    ~temp()
    {
        delete intPtr;
    }
  private:
    int* intPtr;
};
void f (temp fInput)
{
    cout << "f called" << endl;
}
int main()
{
    temp x = 2;
    f(x);
    return 0;
}

您违反了的三条规则

您维护一个指针成员,并将对象的副本传递给函数f。因此,最终结果是在同一指针上调用delete两次。

由于传递x的方式而发生崩溃。

f函数的作用域之后,将调用x的析构函数并删除intPtr

但是,这将删除仍在main作用域中的内存。因此,在调用return 0之后,它将尝试删除已经存在的内存,因为您在同一指针上调用了两次delete。

要修复此错误,请更改

void f (temp fInput)

void f (const temp& fInput)

或者,您可以考虑使用std::shared_ptr。

当传递x(隐式复制构造函数)时,指针被复制,析构函数被调用两次(函数返回之前和main返回之前),因此内存被删除两次。

此处使用std::shared_ptr<int>而不是原始int指针(假设您希望行为相同,即从两个temp引用相同的int;否则,请自己实现复制构造函数、移动构造函数和赋值运算符)。

#include <memory>
class temp {    
public:
  temp(int i) : intPtr(std::make_shared<int>(i)) {
  }
private:
  std::shared_ptr<int> intPtr; // reference counting ftw
};

您在这里遇到的问题是双重删除。因为您没有在这里定义任何复制构造函数,C++很乐意为您定义。该实现通过执行所有内容的浅层复制来实现这一点。

f(x);  

这一行通过创建x的副本并将其传递给f来工作。此时,有2个temp实例拥有一个intPtr成员。两个实例都会删除该指针,这很可能是导致崩溃的原因。

要解决这个问题,你可以采取一些步骤

  1. 使用用于共享的指针类型,如shared_ptr<T>
  2. 创建一个不可调用的副本构造函数,强制实例由ref传递

#2的一个例子是

class temp {
  temp(const temp& other);
  temp& operator=(const temp& other);
public:
  // Same
};

现在f(x)行根本无法编译,因为它无法访问必要的复制构造函数。它强制它重新定义f以防止复制。

void f(const temp& fInput) {
  ...
}