// 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) {
附注
delete
与 nullptr
(代码中 NULL
的现代 C++11 版本)指针配合得很好,所以你不需要在调用delete
之前需要冗余的if (ptr)
检查。
关于c++ - 为什么这个删除仍然导致运行时异常即使我在删除后将指针设置为NULL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40282588/