2013-12-04 4 views
-1

У меня есть оператор извлечения, который используется для класса с 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 тело:

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;

В главном драйвере:

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; 
}; 
+0

Показать код для функции stringCopy. Вероятно, вы должны использовать std :: string, если вы все равно используете C++. –

+0

Почему вы говорите, что 'stringCopy' делает« глубокую »копию? Является ли 'name' тоже объектом? Пожалуйста, напишите 'stringCopy' и' Player'. – KeithSmith

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

+0

Я не изначально сформулировал это очень четко в вопросе, но проблема в том, что при втором вызове линии, которая выделяет память на «temp», адрес новой памяти является ТОЛЬКО как уже используемым массив 'name'. – Bobazonski

+0

Правильно, и нет проблем, что 'temp' получает одну и ту же память, потому что вы освободили ее для повторного использования с помощью' delete [] '. Или вы говорите, что '& currentPlayer.name == temp'? Этого не должно быть. Покажите нам вывод, напечатанный вашим кодом отладки. –

+0

@ user1362548: так что покажите нам класс игрока и как память для .name будет выделена/освобождена .... –

Смежные вопросы