c++ - 为什么这个删除仍然导致运行时异常即使我在删除后将指针设置为NULL

标签 c++ debugging memory-management copy delete-operator

// CplusTest20161027.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"


#include <iostream>

using namespace std;

class Line {
public:
    int getLength(void);
    Line(int len);             // simple constructor
                               // Line( const Line &obj);  // copy constructor
    ~Line();                     // destructor

private:
    int *ptr;
};

// Member functions definitions including constructor
Line::Line(int len) {
    cout << "Normal constructor allocating ptr" << endl;

    // allocate memory for the pointer;
    ptr = new int;
    *ptr = len;
}

//Line::Line(const Line &obj) {
//   cout << "Copy constructor allocating ptr." << endl;
//   ptr = new int;
//   *ptr = *obj.ptr; // copy the value
//}

Line::~Line(void) {
    cout << "Freeing memory!" << endl;
    if (ptr)
    {
        delete ptr;
        ptr = NULL;
    }
}

int Line::getLength(void) {
    return *ptr;
}

void display(Line obj) {
    cout << "Length of line : " << obj.getLength() << endl;
}

// Main function for the program
int main() {
    Line line(10);

    display(line);

    return 0;
}

在上面的代码中,我注释了复制结构来测试发生了什么。我发现指针会被删除两次,所以这是一个异常(exception)。 所以我决定通过在删除后设置 prt=NULL 来检查指针是否应该被删除。 但 ptr 仍然会被删除两次。为什么? 有人可以向我解释一下逻辑吗? 请帮我弄清楚出了什么问题? 输出是: 分配 ptr 的普通构造函数 线长:10 释放内存! 释放内存!

堆上有异常。

最佳答案

我认为问题在于您将 Line 对象按值传递给 display 函数:

void display(Line obj) {

然后在调用站点:

Line line(10);
display(line);

这会生成 line拷贝,并且默认复制构造函数将执行逐成员复制Line 的成员,即它的 int* ptr 指针。

因此,有两次析构函数调用:一次针对原始 line 对象,一次针对拷贝,您将获得双重销毁。

第一个析构函数调用正确删除最初分配的堆内存。
但是第二个析构函数调用尝试删除在上一次调用中已经删除的内存。

您应该禁止复制,或者为您的 Line 类实现正确的复制语义。

要禁止复制,您可以对复制构造函数和复制赋值使用 C++11 =delete 语法 operator=,例如:

class Line {
 public:
  ... 
  // Ban copy
  Line(const Line&) = delete;
  Line& operator=(const Line&) = delete;
};

如果您禁止复制,您仍然可以传递 Line 对象,例如通过 const& 到函数:

void display(Line const& obj) {

附注
deletenullptr (代码中 NULL 的现代 C++11 版本)指针配合得很好,所以你不需要在调用delete之前需要冗余的if (ptr)检查。

关于c++ - 为什么这个删除仍然导致运行时异常即使我在删除后将指针设置为NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40282588/

相关文章:

c++ - 重命名文件路径和 Doxygen

C++ 使用函数指针重写纯虚函数

C++ 调试 '<<' 未找到运算符

c# - 搜索代码库的所有执行路径以查看调用 "Int.TryParse"的位置

c# - 在 Visual Studio 中更改下一行执行时的意外后果

c++ - C++中的全局变量内存分配

c++ - 像 int (x) 这样的声明的目的是什么?或 int (x) = 10;

C++、枚举和 OR 条件

java - 启动 Cassandra 3.4 时出错

Android和图像回收