// 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;
}
在上面的代码中,我评论了复制结构来测试发生了什么。我发现指针会被删除两次,所以它是一个例外。 所以我决定通过在删除后设置prt = NULL来检查是否应该删除指针。 但是,ptr将删除TWICE。为什么? 有人可以向我解释这个逻辑吗? 请帮我弄清楚出了什么问题? 输出是: 普通构造函数分配ptr 线长:10 释放记忆! 释放记忆!
堆上有例外。
答案 0 :(得分:2)
我认为问题是您将Line
对象按值传递给display
函数:
void display(Line obj) {
然后在通话网站:
Line line(10); display(line);
这会使line
的副本,默认副本构造函数将执行{{>成员明智的副本{{ 1}}&#39;成员,即其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&
<强> P.S。强>
void display(Line const& obj) {
与delete
(代码中的nullptr
的现代C ++ 11版本)指针一样正常,因此您不需要冗余NULL
在致电if (ptr)
之前检查。