我有一个提取运算符用于具有 char * member'name'的类。这是我的主要驱动程序的代码:
Player tempPlayer;
for(int i=0;i<4;i++){
fin >> tempPlayer;
}
然后我继续用提取的播放器做一些事情(这是无关紧要的),但问题是每次使用提取操作符时,都会发生奇怪的事情。以下是运算符的定义:
ifstream& operator>>(ifstream& fin, Player& currentPlayer){
char* temp = new char[50];
char tempChar;
fin >> temp;
// importing from a file that contains names of about 6 characters each
stringCopy(currentPlayer.name, temp);
delete[] temp;
temp = NULL;
return fin;
}
stringCopy body:
void stringCopy(char *destPtr, const char *sourcePtr){
while(*sourcePtr!='\0'){
*destPtr = *sourcePtr;
destPtr++;
sourcePtr++;
}
*destPtr='\0';
}
我一直在调试,打印出用于temp
的内存地址和名称。
第一次调用提取运算符时,播放器的名称和temp
数组具有不同的内存地址,这应该是应该发生的。然后删除temp并将其设置为NULL,我通过打印地址(并获得'0')确认,并且在函数返回后,播放器名称的地址仍然存在。
但是,在后续通话中,temp
和玩家姓名的地址将与第一个玩家姓名的地址相同。名称地址应该是相同的,因为它只是被覆盖的同一个对象,但是如果temp
分配了new char[]
个关键字,为什么cout << "temp address followed by name address: " << (void*)temp << " " << (void*)(currentPlayer.name) << endl;
将SAME地址作为“名称”? / p>
以下是我在调试时使用的一些代码:
沿着运营商身体的每一步:
cout << "player " << i+1 << " has been extracted with name address " << (void*)(tempPlayer.name) << endl;
在主驱动程序中:
Player
以下是Player::Player(){
name = new char[50];
stringCopy(name,"name");
ID = new int[5];
}
构造函数:
class Player{
public:
char* name;
};
排除不相关的数据成员,这里是播放器定义:
{{1}}
答案 0 :(得分:0)
当您delete[]
某事new[]
时,标准库可以重用该内存。因此,temp
最终会一次又一次地获得相同的地址,这并不奇怪。这是预期的行为,而不仅仅是一个问题。
真正的问题是,在你的“驱动程序”代码中(你没有向我们展示过一些代码),你在某处有一个tempPlayer
的浅表副本。这将指针复制到name
,而不分配新存储。删除该副本后,Player
的析构函数将删除此浅层副本中的name
,并将name
释放到堆中。
现在原始指向释放的内存。将来调用operator>>
然后分配这个现在可以说是免费的内存。糟糕!
您的短期解决方法是删除浅层副本。从长远来看,正确的解决方法是实现正确的复制和复制赋值构造函数,按照“3规则”(http://en.wikipedia.org/wiki/Rule_of_three_%28C++_programming%29),或者如果你想真正对C ++ 11友好,那么规则是-5。 (相同的链接。)
或者,您可以考虑将复制和复制赋值构造函数设置为私有,这样可以防止这些对象的不需要的副本。 (这里有一些提示:What's the most reliable way to prohibit a copy constructor in C++?)