2013-03-22 4 views
1

Должен ли я освободить динамический массив (выделен в конструкторе) в конструкторе копирования и/или операции присваивания?Выделение динамического массива (оператор присваивания против конструктора копирования)

struct Test 
{ 
    const size_t n; 
    int* xs; 

    Test(const size_t n) 
    : n(n) 
    , xs(new int[n]) 
    { } 

    Test(const Test& other) 
    : n(other.n) 
    , xs(new int[n]) 
    { 
    memcpy(xs, other.xs, n * sizeof(int)); 
    } 

    Test& operator=(const Test& other) 
    { 
    n = other.n; 
    delete[] xs; 
    xs = new int[n]; 
    memcpy(xs, other.xs, n * sizeof(int)); 
    } 

    ~Test() 
    { 
    delete[] xs; 
    } 
}; 

void main() 
{ 
    Test a(10); 
    Test b(a); 
    Test c(20); 
    c = b; 
} 

Как вы можете видеть, я думаю, что вы должны delete[] массив в реализации оператора присваивания (так как было уже выделено где-то в процессе строительства объекта, который будучи назначен). И я думаю, что вам не нужно выделять массив при копировании объекта, так как он еще не создан.

Дело в том, что выполнение приложения выше под Application Verifier не показывает утечки памяти, независимо от того, есть ли delete[] в operator= или нет. Приложение работает нормально, хотя в обоих случаях.

Итак, должен ли я delete[] xs в конструкторе копирования, оператор присваивания, оба или ни один?

+0

'Test & operator = (const Test & other) : n (other.n)' compiled? И да, вы должны. –

+0

@ LuchianGrigore нет, я набрал его без компиляции (у меня нет компилятора на компьютере, с которого я просматриваю SO). Спасибо, что заметили! –

+0

@ LuchianGrigore Но почему Application Verifier не обнаруживает утечек памяти в обоих случаях? Разве это не заслуживающий доверия инструмент? –

ответ

0

В целом, управление памятью вручную - это идея bad. Вы не должны этого делать, и вы должны предпочесть std::vector<> или другие классы контейнеров, если у вас нет веских оснований для этого. Это сказано ...

Итак, следует ли удалить [] xs в конструкторе копирования, оператор присваивания, оба или ни один?

Вы должны delete[] массив, выделенный new[], прежде чем вы потеряете последний указатель на этот массив. В противном случае вы просочитесь.

На практике, так как массив, который вы хотите удалить, принадлежит и инкапсулирован вашим классом, это означает, что вам придется delete[] его в перегрузке оператора присваивания (до того, как указатель получит новый массив, тем самым потеряв только существующая ссылка на предыдущую) и в деструкторе (когда вы удаляете объект, а затем теряете только существующую ссылку на инкапсулированный массив).

Как вы говорите, конструктор копирования является строкой построения, и указатель ранее не ссылался на какой-либо выделенный ресурс (фактически, здесь нет «ранее», срок жизни объекта еще не начался): поэтому, здесь не только не нужно delete[], это неправильно.

Также обратите внимание, что во избежание оборванных указателей и возможного неопределенного поведения вы должны убедиться, что ваш класс действительно является единственным владельцем инкапсулированного массива. В противном случае код, внешний для класса, может быть delete[] или сохранить указатели на него, которые станут свисающими. Таким образом, вы не должны делать xs членом данных public.

+0

Спасибо, сейчас я придерживаюсь этого. Я беспокоился о том, что показывает Application Verifier, но ваш ответ, очевидно, имеет смысл для меня, поэтому вверните его. –

+0

@EgorTensin: Да, я бы тоже сказал, что это тоже. Или, возможно, задайте конкретный вопрос о том, что нужно сделать, чтобы приложение Verifier обнаружило утечки. К сожалению, я не знаю этого инструмента, поэтому я не могу с этим поделать. –

+0

Учитывая ваш совет '' std :: vector'', вы можете просмотреть комментарии к вопросу (в случае, если вам интересно). –

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