很诡异的指针问题

wangdong20 2013-11-01 04:51:02
问题有点乱,我理一理慢慢表述下
首先是一个Person类,代码如下
#include "Date.h"

class Person
{
public:
Person(int id, int year, int month, int day);
Person(Person &); // 问题出在这个方法里
~Person();
int getId();
Date* getBirthDate(); // return the pointer of the object

private:
int id;
Date* birthDate; // The pointer of the object
};

可以看到里面有Date类,代码如下
#ifndef DATE_H
#define DATE_H

class Date{
public:
Date(int newYear, int newMonth, int newDay);
int getYear();
void setYear(int year);

private:
int year;
int month;
int day;
};

#endif

我把Person类的拷贝方法重写了
Person::Person(Person &person){
id = person.id;
Date *p = person.getBirthDate();
birthDate = new Date(*p); // 调试的时候一切正常
}

调用了
Person person1(111, 1970, 5, 3);
Person person2(222, 2000, 11, 8);
person1 = Person(person2); // Copy person2 to person1

就在调试的时候Person(person2)这个方法内部还是正常的,
返回的Person类里的数据也还是和Person2一样,可一到执行person1 = Person()时
地址没有变化,Person类里面的Date部分地址也没变,
当然Person下的id也没变是正常的,就是Date地址下的值全部是随机值了
这是什么原因导致的
...全文
684 40 打赏 收藏 转发到动态 举报
写回复
用AI写文章
40 条回复
切换为时间正序
请发表友善的回复…
发表回复
rmaly 2013-11-11
  • 打赏
  • 举报
回复
引用 14 楼 ayrb13 的回复:
基本问题搞清楚了 person1 = Person(person2); 你先构造了一个临时Person变量,然后赋值给person1。 但是因为你没有重写operator=,所以这一步的赋值是一个浅拷贝过程,你把临时变量里面的birth指针复制给了person1,但是临时变量马上就析构了,临时变量里面的birth指针指向的birth对象也肯定析构了(我相信你会在Person的析构函数中实现这个delete),所以person1中的birth指针变成了野指针。 然后,就没有然后了。
顶一个,写一个赋值构造函数进行深拷贝就好了
  • 打赏
  • 举报
回复
引用 2 楼 wangdong20 的回复:
[quote=引用 1 楼 baihacker 的回复:] 你是不是少写了一个operator =?
才学C++,有必要写一个operator =?吗[/quote] 如果你定义了析构,拷贝构造,和operator=的其中一个,应该把这3个都要定义上。这个是C++的三法则。 还有,拷贝构造,最好是拷贝构造的参数前面加一个 const,来以防参数被修改。
wangdong20 2013-11-10
  • 打赏
  • 举报
回复
引用 37 楼 baihacker 的回复:

#include <cstdio>
#ifndef DATE_H
#define DATE_H

class Date{
public:
	Date(int newYear, int newMonth, int newDay) : year(newYear), month(newMonth), day(newDay){}
	int getYear(){return year;}
	void setYear(int newYear){year=newYear;}

private:
	int year;
	int month;
	int day;
};

#endif
//#include "Date.h"

class Person
{
public:
	Person(int id, int year, int month, int day) : id(id), birthDate(new Date(year, month, day)){}
	Person(Person &person){
		id = person.id;
		Date *p = person.getBirthDate();
		birthDate = new Date(*p);  // 调试的时候一切正常
	}
	~Person(){delete birthDate;}
	int getId(){return id;}
	Date* getBirthDate(){return birthDate;};  // return the pointer of the object

	Person& operator = (const Person& other)
	{
		Date* temp = new Date(*other.birthDate);
		delete birthDate;
		birthDate = temp;
		id = other.id;
		return *this;
	}
private:
	int id;
	Date* birthDate;  // The pointer of the object
};
int main()
{
	Person person1(111, 1970, 5, 3);
	Person person2(222, 2000, 11, 8);
    person1 = Person(person2);  // Copy person2 to person1
	printf("%d\n", person1.getBirthDate()->getYear());
	return 0;
}

楼主33楼的问题在于 Date* getBirthDate() 不是常函数(后面要长const小尾巴的才是常函数) 而Person& Person::operator=(const Person& person) 中形参person是一个常引用,所以 birthDate = new Date(*(person.getBirthDate())); 不能编译过,因为不能直接调用常函数。 在这里,不需要通过getBirthDate来访问birthDate,如我10楼代码,没有用getBirthDate。 另一方面,代码没有判断this和另一个操作数是不是同一个,每次先保证new一个birthDate出来,再 释放已有的,然后拷贝id,指针赋值,保证这个时候不出错。
birthDate = new Date(*(person.getBirthDate())); 不能编译过,因为不能直接调用常函数。 不能直接调用常函数是什么意思,person不能调用常函数吗 我想把Date*封装为private的变量
baihacker 2013-11-10
  • 打赏
  • 举报
回复

#include <cstdio>
#ifndef DATE_H
#define DATE_H

class Date{
public:
	Date(int newYear, int newMonth, int newDay) : year(newYear), month(newMonth), day(newDay){}
	int getYear(){return year;}
	void setYear(int newYear){year=newYear;}

private:
	int year;
	int month;
	int day;
};

#endif
//#include "Date.h"

class Person
{
public:
	Person(int id, int year, int month, int day) : id(id), birthDate(new Date(year, month, day)){}
	Person(Person &person){
		id = person.id;
		Date *p = person.getBirthDate();
		birthDate = new Date(*p);  // 调试的时候一切正常
	}
	~Person(){delete birthDate;}
	int getId(){return id;}
	Date* getBirthDate(){return birthDate;};  // return the pointer of the object

	Person& operator = (const Person& other)
	{
		Date* temp = new Date(*other.birthDate);
		delete birthDate;
		birthDate = temp;
		id = other.id;
		return *this;
	}
private:
	int id;
	Date* birthDate;  // The pointer of the object
};
int main()
{
	Person person1(111, 1970, 5, 3);
	Person person2(222, 2000, 11, 8);
    person1 = Person(person2);  // Copy person2 to person1
	printf("%d\n", person1.getBirthDate()->getYear());
	return 0;
}

楼主33楼的问题在于 Date* getBirthDate() 不是常函数(后面要长const小尾巴的才是常函数) 而Person& Person::operator=(const Person& person) 中形参person是一个常引用,所以 birthDate = new Date(*(person.getBirthDate())); 不能编译过,因为不能直接调用常函数。 在这里,不需要通过getBirthDate来访问birthDate,如我10楼代码,没有用getBirthDate。 另一方面,代码没有判断this和另一个操作数是不是同一个,每次先保证new一个birthDate出来,再 释放已有的,然后拷贝id,指针赋值,保证这个时候不出错。
baihacker 2013-11-10
  • 打赏
  • 举报
回复
引用 35 楼 wangdong20 的回复:
[quote=引用 10 楼 baihacker 的回复:]
Date* temp = new Date(*other.birthDate);
delete birthDate;
birthDate = temp;
id = other.id;
你是说这个吗?不管用啊[/quote] 不管用的细节?
wangdong20 2013-11-04
  • 打赏
  • 举报
回复
引用 10 楼 baihacker 的回复:
Date* temp = new Date(*other.birthDate);
delete birthDate;
birthDate = temp;
id = other.id;
你是说这个吗?不管用啊
baihacker 2013-11-04
  • 打赏
  • 举报
回复
引用 33 楼 wangdong20 的回复:
[quote=引用 27 楼 ayrb13 的回复:] [quote=引用 24 楼 wangdong20 的回复:] 我的代码编译不通过,代码如下
Person::Person(Person &person){
	this->operator = person;
}
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
	birthDate = new Date(*person.getBirthDate());
    return *this;
}
错误是不能将this指针从const Person转换为Person &就在birthDate = new Date(*person.getBirthDate());这一行
birthDate = new Date(*(person.getBirthDate())); 再试试?。。。[/quote] birthDate = new Date(*(person.getBirthDate())); 为什么总是这句编译不通过,显示不能将this指针从const Person转化为Person &[/quote] 有没有试过我给的代码?
wangdong20 2013-11-04
  • 打赏
  • 举报
回复
引用 27 楼 ayrb13 的回复:
[quote=引用 24 楼 wangdong20 的回复:] 我的代码编译不通过,代码如下
Person::Person(Person &person){
	this->operator = person;
}
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
	birthDate = new Date(*person.getBirthDate());
    return *this;
}
错误是不能将this指针从const Person转换为Person &就在birthDate = new Date(*person.getBirthDate());这一行
birthDate = new Date(*(person.getBirthDate())); 再试试?。。。[/quote] birthDate = new Date(*(person.getBirthDate())); 为什么总是这句编译不通过,显示不能将this指针从const Person转化为Person &
赵4老师 2013-11-04
  • 打赏
  • 举报
回复
《深度探索C++对象模型》 《C++反汇编与逆向分析技术揭秘》
赵4老师 2013-11-04
  • 打赏
  • 举报
回复
引用 29 楼 wangdong20 的回复:
[quote=引用 28 楼 zhao4zhong1 的回复:] 计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
又是赵老师的神贴回复,能不能讲点实际的[/quote] 你不觉得C++语句都是虚无缥缈的,只有其对应的汇编指令才是比较实际的吗?
xiaoyao18301 2013-11-04
  • 打赏
  • 举报
回复
可一到执行person1 = Person()时 这个是调用Person.operator=()函数 而且Person类中有指针成员Data *,所以operator=()函数必须要重新的,如果你用编译器默认给你创建的,肯定会有问题的。 另外奇怪,为什么是Person(Person &); 而不是Person(const Person &); 你不想高效点吗?
wangdong20 2013-11-04
  • 打赏
  • 举报
回复
引用 28 楼 zhao4zhong1 的回复:
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
又是赵老师的神贴回复,能不能讲点实际的
赵4老师 2013-11-04
  • 打赏
  • 举报
回复
计算机组成原理→DOS命令→汇编语言→C语言(不包括C++)、代码书写规范→数据结构、编译原理、操作系统→计算机网络、数据库原理、正则表达式→其它语言(包括C++)、架构…… 对学习编程者的忠告: 眼过千遍不如手过一遍! 书看千行不如手敲一行! 手敲千行不如单步一行! 单步源代码千行不如单步对应汇编一行! 单步类的实例“构造”或“复制”或“作为函数参数”或“作为函数返回值返回”或“参加各种运算”或“退出作用域”的语句对应的汇编代码几步后,就会来到该类的“构造函数”或“复制构造函数”或“运算符重载”或“析构函数”对应的C/C++源代码处。 VC调试时按Alt+8、Alt+7、Alt+6和Alt+5,打开汇编窗口、堆栈窗口、内存窗口和寄存器窗口看每句C对应的汇编、单步执行并观察相应堆栈、内存和寄存器变化,这样过一遍不就啥都明白了吗。 对VC来说,所谓‘调试时’就是编译连接通过以后,按F10或F11键单步执行一步以后的时候,或者在某行按F9设了断点后按F5执行停在该断点处的时候。 (Turbo C或Borland C用Turbo Debugger调试,Linux或Unix下用GDB调试时,看每句C对应的汇编并单步执行观察相应内存和寄存器变化。)
ayrb13 2013-11-04
  • 打赏
  • 举报
回复
引用 24 楼 wangdong20 的回复:
我的代码编译不通过,代码如下
Person::Person(Person &person){
	this->operator = person;
}
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
	birthDate = new Date(*person.getBirthDate());
    return *this;
}
错误是不能将this指针从const Person转换为Person &就在birthDate = new Date(*person.getBirthDate());这一行
birthDate = new Date(*(person.getBirthDate())); 再试试?。。。
wangdong20 2013-11-02
  • 打赏
  • 举报
回复
引用 23 楼 sniffer12345 的回复:
C++蛋疼的地方就在于,楼主明明就想只写一个简单的类,结果拷贝赋值了,构造赋值了就都出来了,还TMD得删指针!哦,还别忘了,析构的时候还得记得再删一次!birthDate还得记得初始化,要不照样崩! 难怪越来越没人喜欢
才学C++,感觉C++好坑人啊,我是不是该放弃了
wangdong20 2013-11-02
  • 打赏
  • 举报
回复
我的代码编译不通过,代码如下
Person::Person(Person &person){
	this->operator = person;
}
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
	birthDate = new Date(*person.getBirthDate());
    return *this;
}
错误是不能将this指针从const Person转换为Person &就在birthDate = new Date(*person.getBirthDate());这一行
sniffer12345 2013-11-01
  • 打赏
  • 举报
回复
C++蛋疼的地方就在于,楼主明明就想只写一个简单的类,结果拷贝赋值了,构造赋值了就都出来了,还TMD得删指针!哦,还别忘了,析构的时候还得记得再删一次!birthDate还得记得初始化,要不照样崩! 难怪越来越没人喜欢
lm_whales 2013-11-01
  • 打赏
  • 举报
回复
感到这么做就挺好:
struct Date{
public:
    Date(int newYear, int newMonth, int newDay):year(newYear),month(newMonth),day(newDay){};
    Date(const Date &ref ):year(ref.year),month(ref.month),day(ref.day){};
    Date operator=(const Date &ref){
    year =ref.year;month = ref.month; day =ref.day;
    return *this;
    };

    int year;
    int month;
    int day;
};
class Person
{
public:
    Person(int id, int year, int month, int day);
    Person(int id, const Date & ref);
    Person(const Person &);  
  
    int getId()const{return id;};
    const Date getBirthDate()const{return birthDate;};  
    Person& Person::operator=(const Person& person);
private:
    int id;
    Date birthDate;  // The pointer of the object
}; 

Person::Person(int id, int year, int month, int day):id(id),birthDate(year,month,day){} 
Person(int id, const Date & ref):id(ref.id),birthDate(ref.birthDate){}
Person::Person(const Person & ref):id(ref.id),birthDate(ref){}

Person& Person::operator=(const Person& person){
    if(this ==&person)return *this;
    id = person.id;
    birthDate = person.birthDate ;
    return *this;
}
还有多远 2013-11-01
  • 打赏
  • 举报
回复
引用 20 楼 wangdong20 的回复:
[quote=引用 17 楼 ayrb13 的回复:] 你的返回类型有问题 operator=的返回类型必须是这个类的引用 需要这么写
Person& Person::operator=(const Person& other)
{
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
    Date *p = person.getBirthDate();
    birthDate = new Date(*p);
    return *this;
}
还是有问题
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
Date *p = person.getBirthDate();//编译的时候显示不能将this指针从const Person转化为Person&
    birthDate = new Date(*p);
    return *this;
}
[/quote] 恩,是有个问题,直接birthDate = new Date(*person.getBirthDate());
wangdong20 2013-11-01
  • 打赏
  • 举报
回复
引用 17 楼 ayrb13 的回复:
你的返回类型有问题 operator=的返回类型必须是这个类的引用 需要这么写
Person& Person::operator=(const Person& other)
{
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
    Date *p = person.getBirthDate();
    birthDate = new Date(*p);
    return *this;
}
还是有问题
Person& Person::operator=(const Person& person){
    if(birthDate)
        delete birthDate;//若对象已有birthData,需要析构再创建,避免出现内存泄露
    id = person.id;
Date *p = person.getBirthDate();//编译的时候显示不能将this指针从const Person转化为Person&
    birthDate = new Date(*p);
    return *this;
}
加载更多回复(19)

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧