2010-06-07 5 views
2

Пожалуйста, взгляд на эту программу:конструктор копирования демо (Грохот ... случай 2)

class CopyCon 
{ 
public: 
char *name; 

CopyCon() 
{ 
    name = new char[20];   
    name = "Hai";//_tcscpy(name,"Hai"); 
} 

CopyCon(const CopyCon &objCopyCon) 
{ 
    name = new char[_tcslen(objCopyCon.name)+1]; 
    _tcscpy(name,objCopyCon.name); 
} 

~CopyCon() 
{ 
    if(name != NULL) 
    { 
     delete[] name; 
     name = NULL; 
    } 
} 
}; 

int main() 
{ 
    CopyCon obj1; 
    CopyCon obj2(obj1); 
    cout<<obj1.name<<endl; 
    cout<<obj2.name<<endl; 
} 

Эта программа выходит из строя при выполнении. Ошибка: «Выражение: _BLOCK_TYPE_IS_VALID (pHead-> nBlockUse)»

Если я назначу «Hai», чтобы назвать с помощью оператора назначения, его сбой. Где, когда я использую string func _tcscpy для присвоения имени «Hai», его работа отлично. Может кто-нибудь объяснить, почему так?

+0

Это смешно, как только 10k пользователи репутации отправить ответ к вашей проблеме. И в основном все говорят то же самое. Означает ли это, что вы получаете доступ к знаниям более высокого уровня при достижении репутации 10 000? – DaClown

+0

Вам не нужно проверять значение null перед удалением. передача NULL для удаления - это нормально. –

+2

Почему вы используете '_tcslen' и' _tcscpy' с массивом 'char'? –

ответ

3

В конструкторе по умолчанию

CopyCon() 
{ 
    name = new char[20];   
    name = "Hai";//_tcscpy(name,"Hai"); 
} 

присвоить адрес строкового литерала к указателю и в деструкторе вы называете delete[] на нем, это неопределенное поведение. delete[] следует вызывать только по адресам, возвращаемым new[].

Если вы используете _tcscpy(), вы копируете литеральное содержимое в буфер, выделенный new[], а затем деструктор работает нормально.

2

Когда вы используете назначение, вы указываете указатель name на строковый литерал «Hai». Это позже будет удалено в деструкторе. Однако строковый литерал не был выделен new и не может быть удален таким образом, чтобы вы получили неопределенное поведение. Вы можете освободить только delete вещей, которые вы выделили new. Это не имеет никакого отношения к конструктору копирования.

4
name = "Hai";//_tcscpy(name,"Hai"); 

Вы не копируете содержимое «Хай» в name вместо name будет указывать только для чтения памяти (содержимое которого «Хай») , если вы попытаетесь удалить имя позже тогда мощь аварии.

+0

Здесь больше нечего сказать. – fmuecke

+0

За исключением того, что C++ не гарантирует, что «Hai» хранится в постоянной памяти. – 2010-06-07 08:26:12

+1

Это гарантирует, что вызов delete [] в строковом литерале приводит к неопределенному поведению uin. –

0

Что вы делаете в этом коде, так это то, что вы выделяете блок памяти для имени (присваиваете адрес указателю на имя). Затем вы фактически перезаписываете этот адрес по адресу строкового литерала «Hai» (который перестает существовать после завершения конструктора). Вот почему вы получаете ошибку, так как деструктор пытается освободить память, которая не принадлежит вам. (Вы не выделили его).

2
name = new char[20];   
name = "Hai";//_tcscpy(name,"Hai"); 

Здесь вы не копирование данных в памяти, выделенной new. Вместо этого вы назначаете новое значение указателю name, который указывает на местоположение только для чтения (в большинстве случаев). Поскольку эта память не была выделена с использованием new, вы не можете сделать delete. Также обратите внимание, что у вас здесь утечка памяти, так как память, выделенная с использованием new char[20];, никогда не удаляется.

2

Сама же программа, но в C++:

struct CopyCon 
{ 
    CopyCon(): name("HAI") {} 
    std::string name; 
}; 

int main(int argc, char* argv[]) 
{ 
    CopyCon obj1; 
    CopyCon obj2(obj1); 
    cout<<obj1.name<<endl; 
    cout<<obj2.name<<endl; 
} 

Шахта работает, ясно, и я набрал меньше, чем вы делали;)

+0

+1 для показа 'реального' C++. – xtofl