2

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

#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;
}
4

4 回答 4

5

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

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

#include <memory>

class temp {    
public:
  temp(int i) : intPtr(std::make_shared<int>(i)) {

  }

private:
  std::shared_ptr<int> intPtr; // reference counting ftw
};
于 2012-04-04T21:20:15.413 回答
5

发生崩溃的原因是您通过的方式x

f函数作用域之后,x将调用 's destructure 并删除intPtr

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

要修复此错误,请更改

void f (temp fInput)

void f (const temp& fInput)

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

于 2012-04-04T21:20:23.370 回答
5

你违反了三法则

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

于 2012-04-04T21:20:50.897 回答
1

您在这里遇到的问题是双重删除。因为您没有在这里定义任何复制构造函数,所以 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) {
  ...
}
于 2012-04-04T21:21:03.650 回答