2010-09-30 8 views
6

Dlaczego nie mogę tego zrobić?Zwiększ zadanie Shared_Ptr

boost::shared_ptr<QueuList> next; 

void QueuList::SetNextPtr(QueuList* Next) 
{ 
    boost::mutex mtx; 

    boost::mutex::scoped_lock lock(mtx); 
    {// scope of lock 
     //if (next == NULL) // is this needed on a shared_ptr?? 
     next = Next; // Why can I not assign a raw ptr to a shared_ptr???? 
    } 

}

Jak mam to zrobić zamiast ??

EDYCJA: Wywołanie tej metody, gdy następna zmienna jest przypisana poprawnie, nadal powoduje błąd, gdy obiekt QueuList zostanie z jakiegoś powodu zniszczony. Otrzymuję asercję debugowania. Niszczyciel obiektu nie robi nic szczególnego. Rozbił się tylko, gdy zadzwonię do tej funkcji:

QueuList li; 
    QueuList lis; 

    li.SetNextPtr(&lis); 

Po wyjściu poza zakres, otrzymuję potwierdzenie debugowania ... Jakieś pomysły?

+1

redakcją moją odpowiedź za edycję. –

Odpowiedz

5

Umieszczenie wskaźnika wewnątrz własności shared_ptr transferów wskaźnik do shared_ptr, więc shared_ptr jest odpowiedzialny za usunięcie go. Operacja ta jest koncepcyjnie ważną operacją, więc projektanci shared_ptr nie chcieli, aby stało się to po prostu normalnie wyglądającym zadaniem. Na przykład, chcieli zapobiec kod jak:

some_shared_ptr = some_other_smart_pointer.get(); 

który wygląda dość niewinnie, ale oznaczałoby, że oba inteligentne wskaźniki myśleli, że odpowiedzialność za sprzątanie wskaźnik, i prawdopodobnie dwukrotnie usunąć wskaźnik lub coś podobnego .

Oto, co dzieje się z twoim stwierdzeniem debugowania. Wywołanie SetNextPtr(&lis) przechodzi na własność na shared_ptr, a "własność" oznacza, że ​​shared_ptr wywoła delete na swoim pointe, gdy ostatnia kopia shared_ptr wykracza poza zakres. Zatem skutecznie usuwasz zmienną lokalną (stos) - lis - która uszkadza stos i powoduje awarię.

+0

, więc jeśli lis jest samym wskaźnikiem, przekazanie go do tej funkcji spowoduje, że będzie ono własnością shared_ptr, czy nadal będę musiał usunąć mój wskaźnik? –

+0

Nie będziesz musiał usuwać wskaźnika 'lis' - musisz tylko" usunąć "wskaźniki uzyskane z' nowego', a tak naprawdę musisz * tylko * wywoływać 'delete' na wskaźnikach, które zostały zwrócone przez' new'. Niepoprawne jest przekazywanie w ogóle funkcji "lis" do tej funkcji, ponieważ funkcja jest obecnie zapisywana, ponieważ '& lis' nie jest wskaźnikiem uzyskanym z' nowego', a funkcja domyślnie "usunie" swój argument. – Doug

+0

Miałem na myśli wskaźnik w następujący sposób: QueuList * lis = new QueuList(); –

7

Robi się to, aby zapobiec przypadkowemu przypisaniu wskaźników do shared_ptr, których czas życia jest zarządzany niezależnie. Musisz jawnie utworzyć shared_ptr, który następnie przejmuje na własność obiekt.

next = boost::shared_ptr<QueueList>(Next); 

Edit o edycję Problem polega na tym, że w przypadku shared_ptr bierze własność obiektu na stosie. Następnie dwie rzeczy mogą się zdarzyć:

  1. Stos ramka obiektu zostanie wyczyszczone przed shared_ptr osiągnie liczbę odniesienia 0. W takim przypadku shared_ptr spróbuje usunąć non-istniejący obiekt gdzieś później, prowadząc do niezdefiniowanego zachowania.
  2. Urządzenie shared_ptr osiąga liczbę odniesienia wynoszącą 0 przed wyczyszczeniem ramki stosu. W takim przypadku spróbuje usunąć obiekt na stosie. Nie wiem dokładnie, co się dzieje w tym przypadku, ale zakładam, że jest to również niezdefiniowane zachowanie.
+5

Lub po prostu użyj funkcji resetowania członka - 'next.reset (Next); ' –

6

Można użyć funkcji reset() zamiast wordier next = boost::shared_ptr<QueueList>(Next);

next.Reset(Next);