2010-12-13 4 views
0

Мне просто интересно узнать, есть ли существенная/серьезная разница в этих трех подходах к вызову деструктора. Рассмотрим следующий код. Также рассмотрите два случая, упомянутых в main().Принятие сравнения подхода деструктора

class Sample 
{ 
public: 
    ~Sample() 
    { 
     cout << "destructor called" << endl; 
    } 
    void destroyApproach1() { this->~Sample(); } 
    void destroyApproach2() { delete this; } 
}; 

void destroyApproach3(Sample *_this) 
{ 
    delete _this; 
} 

void TestUsingNew() 
{ 
    Sample *pSample[] = { new Sample(), new Sample(),new Sample()}; 
    pSample[0]->destroyApproach1(); 
    pSample[1]->destroyApproach2(); 
    destroyApproach3(pSample[2]); 
} 
void TestUsingPlacementNew() 
{ 
    void *buf1 = std::malloc(sizeof(Sample)); 
    void *buf2 = std::malloc(sizeof(Sample)); 
    void *buf3 = std::malloc(sizeof(Sample)); 
    Sample *pSample[3] = { new (buf1) Sample(), new (buf2) Sample(), new (buf3) Sample()}; 
    pSample[0]->destroyApproach1(); 
    pSample[1]->destroyApproach2(); 
    destroyApproach3(pSample[2]); 
} 
int main() 
{ 
    //Case 1 : when using new 
    TestUsingNew(); 

    //Case 2 : when using placement new 
    TestUsingPlacementNew(); 
    return 0; 
} 

Пожалуйста конкретно при ответе, чтобы этого случая вы ответив на: случай 1 или случай 2, или оба!


Кроме того, я пытался написать TestUsingPlacementNew() таким образом, но это бросает исключение во время выполнения (MSVC++ 2008). Я не понимаю, почему:

void TestUsingPlacementNew() 
{ 
    const int size = sizeof(Sample); 
    char *buffer = (char*)std::malloc(size * 3); 
    Sample *pSample[] = { new (buffer) Sample(), new (&buffer[size]) Sample(),new (&buffer[2*size]) Sample()}; 
    pSample[0]->destroyApproach1(); 
    pSample[1]->destroyApproach2(); 
    destroyApproach3(pSample[2]); 
} 

Возможно, может быть причиной заполнения и/или выравнивания памяти?


Похожие темы: Destructor not called after destroying object placement-new'ed

ответ

5

Да, есть огромная разница между этими подходами:

  • В destroyApproach1, вы только вызывать деструктор объекта; вы фактически не освобождаете память, которую он занимал.

  • В destroyApproach2 и destroyApproach3 вызове деструктора объекта и вы освободить память, занимаемую объектом (используя выражение delete). В первом тесте TestUsingPlacementNew оба они также ошибочны, поскольку память, занятая объектом, изначально была выделена вызовом malloc, а не new.

Ошибка выполнения в последнем тесте происходит потому, что вы пытаетесь delete объект с индексом 1 в массиве; указатель на этот элемент изначально не был получен из вызова new. В первом примере он работает только «работает» (где «работает» действительно означает «поведение не определено, но оно по-прежнему функционирует корректно), потому что все три указателя относятся к независимым распределениям кучи.

+0

второй абзац для второго случая при использовании нового места размещения? – Nawaz

+0

@Nawaz: Я обновил ответ, чтобы указать, на какие части я пытался ответить. –

+0

спасибо за обновление :-) – Nawaz

1

delete this это неправильный путь вызвать деструктор в современном коде в общем, вы не должны вызывать деструктор:. их магия является то, что они называются в соответствующее время:

struct A { 
    ~A() { std::cout << "running destructor\n"; } 
}; 

int main() 
{ 
    A a; 
    return 0; 
} 

delete во всех случаях для освобождения памяти, выделенной new . delete this вызовет проблемы, когда объект не был назначен new:

struct B { 
    ~B() { delete this } 
}; 

int main() 
{ 
    B b; 
    return 0; 
} 

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


Размещения new в основном предназначен для водителей аппаратных устройств или других мест, где указатель должен быть выделен в специальном адресе. In general you won't want to destroy objects allocated with placement new. В тех случаях, когда вы хотите, просто вызывать деструктор непосредственно:

My_object* o = new(0xffff) My_object(); 
o->~My_object(); 

Но, помните, Бьярне Страуструп сказал, «явные вызовы деструкторов ... следует по возможности избегать Иногда они необходимы .... Новичок должен подумать трижды, прежде чем вызвать деструктора явно, а также попросить более опытного коллегу, прежде чем делать это »(Язык программирования C++, 10.4.11).

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