2010-02-22 12 views
5

Obecnie studiuję COM i następujący kod myli mnie.W jaki sposób metoda członka może usunąć obiekt?

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "suicide" deletion be possible? 
    return m_refCount; 
} 

Zastanawiam się, w jaki sposób można usunąć instancję obiektu w ramach metody jego elementu? Więc zrobiłem następujący eksperyment:

class A 
{ 
public: 
    void Suicide(void); 
    void Echo(void); 
    char name; 
}; 

void A::Echo(void) 
{ 
    ::printf("echo = %c\n",name); 
} 

void A::Suicide(void) 
{ 
    delete this; 
} 

int main(void) 
{ 
    A a; 
    a.name='a'; 
    a.Suicide(); //failed 
} 

a wykonanie nie powiodło się w a.Suicide(). Raport debugowania zawierał komunikat "Błąd augmentacji debugowania". Czy ktoś mógłby rzucić trochę światła na mnie? Ponieważ jestem całkowicie początkującym na COM.

Podobnym wątek jest tutaj: Question about COM Release() method

Odpowiedz

10

Zmiana głównego na ciało:

A* a = new A(); 
a->name='a'; 
a->Sucide(); 

Można skasować, co zostało zbudowane tylko przez new, oczywiście - nie ma znaczenia, czy to usunięcie jest w funkcji członka lub w innym miejscu.

7

W twoim przykładzie, Suicide() kończy się niepowodzeniem, ponieważ wywołuje usuwanie na obiekcie, który nie został przydzielony dynamicznie, co jest nieważne niezależnie od tego, czy funkcja wywołująca jest członkiem.

funkcje członek może deletethis - jeśli wiedzą wskaźnik this został dynamicznie przydzielane (przez new). Jednak nie mogą one uzyskać dostęp członków po tym punkcie, więc ściśle rzecz biorąc przykład dałeś:

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) 
    delete this; // how could this "sucide" deletion be possible? 
    return m_refCount; 
} 

wyniki w niezdefiniowanej zachowań na rachunku return.

+3

Prosta naprawa to oczywiście powrót do 0. – GManNickG

+0

Dzięki, Michael, odkąd wspomniałeś o "dynamicznej alloacacji", zgaduję, czy istnieje coś przeciwnego "statycznej alloacacji"? co to jest i jaka jest różnica? może trudno to wytłumaczyć jednym słowem. Czy możesz podać mi jakieś odniesienia do dalszych badań? Wielkie dzięki. : D – smwikipedia

+1

@GMan: Chcę tylko wyjaśnić, co masz na myśli: 'if (--m_refCount == 0) {usuń to; return 0; } return m_refCount; '. Nie możesz po prostu zmienić instrukcji return na 'return 0;'. – Dan

1

Użyj new, aby przydzielić nowy przedmiot klasy, który zamierzasz zniszczyć, dzwoniąc pod numer delete.

2

Nie można usunąć obiektu, który nie został przydzielony dynamicznie. Obiekty COM są przydzielane dynamicznie.

to działa:

#include <stdio.h> 

class A 
{ 
public: 
    void Sucide(void); 
    void Echo(void); 
    char name; 
}; 

void A::Echo(void) 
{ 
    ::printf("echo = %c\n",name); 
} 

void A::Sucide(void) 
{ 
    delete this; 
} 

void main(void) 
{ 
    A *a = new A; 
    a->name='a'; 
    a->Sucide(); // works 
} 
3

delete this jest ważna tylko wtedy, gdy obiekt został przydzielony za pomocą operatora new. Dla liczenia odwołań COM nie jest to niezwykłe.

Jest jednak inne zastrzeżenie: dostęp do zmiennych członków po delete this jest niezdefiniowany, ponieważ pamięć obiektu została już zwrócona do wolnego sklepu. Ten pierwszy wysłany przez ciebie kod wykonuje to. Aby to naprawić, użyj zmiennej lokalnej:

STDMETHODIMP_(ULONG) ComCar::Release() 
{ 
    ULONG refCount = --m_refCount; 
    if(refCount==0) 
    delete this; 
    return refCount; 
} 
+1

Osobiście uważam, że jest nieco bardziej zawikłany, ze zmienną lokalną. Jeśli wiesz, że w instrukcji if jest zero, po prostu zwróć 0. – GManNickG

+2

@GMan, ale potrzebujesz dwóch instrukcji zwrotnych, jednego wewnątrz 'if' i jednego na zewnątrz - podejście bk1e zapisuje to duplikowanie! –

+0

Zamiast powielania instrukcji return powielamy wartość \ * shrug \ * Być może ta jest czystsza. – GManNickG

1

Istnieje prosty powód tego. nowe i usunąć muszą pasować.

Więc jeśli utworzysz obiekt w bibliotece dll i przetworzysz go na inną część (exe, dll) środowisko wykonawcze C może być inne. W tym przypadku nie można wywołać polecenia delete, ponieważ środowisko wykonawcze nie ma wiedzy o wskaźniku, który chcesz usunąć. Może się zawiesić.

Z tego powodu jest to dobry projekt do zintegrowania metody samobójstwa. W Com to para metod.

AddRef 
Release 

co oznacza, że ​​wskaźnik ma licznik do zapamiętania, ilu właścicieli ma obiekt. Tylko wtedy, gdy ostatni właściciel wywoła polecenie delete, obiekt jest naprawdę usunięty.

Ale myślę, że wystąpił błąd we wprowadzonej implementacji.

return m_refCount; 

nie powinno być możliwe, gdy obiekt zostanie usunięty. Przynajmniej zachowanie jest niezdefiniowane. Myślę, że musisz zapisać m_refCount na zmiennej lokalnej, aby zwrócić ją w przypadku usunięcia.

STDMETHODIMP _(ULONG) ComCar::Release() 
{ 
    if(--m_refCount==0) { 
    delete this; // how could this "sucide" deletion be possible? 
    return 0; 
    } 
    return m_refCount; 
} 
Powiązane problemy