使用已在使用的内存位置进行动态分配

时间:2013-12-04 02:10:43

标签: c++ memory dynamic

我有一个提取运算符用于具有 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}}

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++?