Какой беспорядок! Вся программа очень трудно читать из-за выбора имен идентификаторов, чтобы начать с:
#ifndef DELETE
#define DELETE(var) delete var, var = NULL
#endif
Я считаю, что очень некрасиво. При использовании классов это кажется очень неудобным. Вы можете использовать его там, где переменные выходят за пределы области видимости, но это трата времени в деструкторе. Я думаю, что было бы Asier обернуть код в некоторых смарт-указатель:
class Teste
{
private:
Teste *_Z;
public:
Teste()
~Teste() // Delete the _Z pointer.
Teste *Z();
void Z(Teste *value);
};
Ok. У вас есть указатель, который вы удаляете в деструкторе. Это означает, что вы берете на себя ответственность за указатель. Это означает, что применяется ule из четырех (аналогично правилу трех, но применимо к правилам собственности). Это означает, что вам в основном нужно написать 4 метода или сгенерированные версии компилятора испортит ваш код. Методы, которые вы должны написать:
A Normal (or default constructor)
A Copy constructor
An Assignment operator
A destructor.
В вашем коде только два из них. Вам нужно написать два других. Или ваш объект не должен владеть указателем RAW. то есть. используйте Smart Pointer.
Teste *_Z;
Это не допускается. Идентификаторы, начинающиеся с символа подчеркивания и буквы capitol, зарезервированы. Вы рискуете превратить макрос ОС в свой код. Прекратите использование подчеркивания в качестве первого символа идентификаторов.
~Teste(){
if (_Z != NULL)
DELETE(_Z);
}
Это не требуется. Простое удаление _Z было бы в порядке. _Z выходит из области видимости, потому что он находится в деструкторе, поэтому нет необходимости устанавливать его в NULL. Оператор delete обрабатывает NULL-указатели просто отлично.
~Test()
{ delete _Z;
}
Teste *Z(){
_Z = new Teste;
return _Z;
}
Что произойдет, если вы звоните Z() несколько раз (PS поставив * рядом с Z, а не рядом с его сделать Тест трудно читать). Каждый раз, когда вы вызываете Z(), переменной-член _Z присваивается новое значение. Но что происходит со старой ценностью? В основном вы просачиваете его. Также, возвращая указатель на объект, принадлежащий внутри Teste, вы даете кому-то еще возможность злоупотреблять объектом (удалите его и т. Д.). Это не хорошо. Этому методу явно не известно.
Teste& Z()
{
delete _Z; // Destroy the old value
_Z = new Teste; // Allocate a new value.
return *_Z; // Return a reference. This indicates you are retaining ownership.
// Thus any user is not allowed to delete it.
// Also you should note in the docs that it is only valid
// until the next not const call on the object
}
void Z(Teste *value){
value->AnyNum = 100;
*_Z = *value;
}
Вы копируете содержимое создаваемого объекта (который содержит указатель) на другой динамически созданный объект! Что произойдет, если _Z не был назначен первым. Конструктор устанавливает его в NULL, поэтому нет гарантии, что он имеет допустимое значение. Любой объект, который вы выделили, также должен быть удален. Но здесь значение динамически распределяется в Z, но никогда не освобождается. Причина, по которой вам это удается, заключается в том, что указатель c с , опущенным в _Z и _Z, удаляется при уничтожении его деструктора.
Teste *b = new Teste, *a;
Это действительно слышал, чтобы читать. Не ленитесь, напишите это правильно. Это считается плохим стилем, и вы никогда не получите от него никакого кода.
Teste* b = new Teste;
Teste* a; // Why not set it to NULL
a = b->Z();
Получение объекта аб для. Но кто уничтожал объект a или b?
b->Z(new Teste);
После этого он становится слишком запутанным.
Вы всегда можете использовать valgrind для проверки утечек памяти , Это очень эффективно. –
Да, я использовал это иногда раньше с C, и это было довольно хорошо. – Jonathan
Я думаю, что лучший способ быть уверенным в том, чтобы не утечка памяти - это не пытаться снять сумасшедшие трюки. Что это: класс, цель которого состоит в том, чтобы удерживать целое число ** и ** пытаться управлять памятью другого динамически распределенного экземпляра самого себя? – UncleBens