2009-09-09 10 views
7

odniesienia w C++ są konstruktu conveneint które pozwalają nam do uproszczenia następujący kod C:shared_ptr i odwołań w C++

f(object *p){ 
    //do something 
} 

int main(){ 
    object* p = (object*) calloc(sizeof(object)); 
    f(p); 
} 

do

f(object& o){ 
    //do something 
} 

int main(){ 
    object o = object(); 
    f(o); 
} 

Wspólne wskaźniki są kolejne udogodnienie w C++, który uprości pamięć zarządzanie. Jednak nie jestem pewien, jak przekazać shared_ptr do funkcji, takich jak f(object& o), który przyjmuje argumenty przez odniesienie?

f(object& o){ 
    //do something 
} 

int main(){ 
    shared_ptr<object> p (new object()); 
    f(*p); 
} 

Czy współużytkowany wskaźnik zostanie inkrementowany, gdy jego obiekt zostanie przekazany przez odniesienie do funkcji?

+2

Zamiast 'object * p = (object *) calloc (sizeof (object));' powinieneś użyć 'object * p = new object(); ', więc konstruktor zostanie wywołany! (Możesz też 'calloc' następnie umieścić' 'new'.) – strager

+1

Powinieneś poczekać kilka godzin, aby dać ludziom czas na znalezienie i odpowiedź na twoje pytanie, albo pójdziesz rzucić shuffle, a ludzie nie będą mieli szansa na poprawienie odpowiedzi dzięki komentarzom. Gdy myślisz, że kurz opadł, wybierz najbardziej pomocną odpowiedź. – GManNickG

+0

Będzie o tym pamiętać w przyszłości. Dzięki! – dzhelil

Odpowiedz

10

Wykonaj shared_ptr według wartości, a liczba odwołań wzrośnie. Jest to łatwiejsze, gdy typedef go:

typedef boost:shared_ptr<object> object_ptr; 

void foo(object_ptr obj) 
{ 
    obj->/* stuff*/; 
    obj.reset(); //only resets this local copy, that means: 
       // reduce reference count (back to 1), and 
       // set obj to point at null. 
} 

int main(void) 
{ 
    object_ptr obj(new object()); 
    foo(obj); 
} 

Należy odniesień umysł są aliasy. Kiedy przechodzisz przez referencję, nie przekazujesz wskaźników, kopii itp. ..., aliasingujesz inny obiekt. (W rzeczywistości są one zaimplementowane jako wskaźniki):

typedef boost:shared_ptr<object> object_ptr; 

void foo(object_ptr& obj) 
{ 
    obj.reset(); // the references was never increased, since a copy has not 
       // been made, this *is* obj in main. so the reference 
       // goes to 0, and obj is deleted 
} 

int main(void) 
{ 
    object_ptr obj(new object); 
    foo(obj); // after this, obj has been reset! 
} 

Zawsze należy pamiętać, aby być const prawidłowa, aby uniknąć błędów:

typedef boost:shared_ptr<object> object_ptr; 

void foo(const object_ptr& obj) 
{ 
    obj.reset(); // cannot do! 
} 

int main(void) 
{ 
    object_ptr obj(new object); 
    foo(obj); 
} 

myślę, że powinniśmy wolisz zdać inteligentne kursory jako odniesienia, gdy to możliwe, unikaj zbędnych przyrostów i dekrementów (oraz kopii i innych).

+3

... i unikaj przekazywania inteligentnych wskaźników jako argumentów, jeśli funkcja nie wymaga inteligentnego wskaźnika (tzn. Nie tworzy kopii do późniejszego użycia). –

2

Czy współużytkowany wskaźnik zostanie inkrementowany, gdy jego obiekt zostanie przekazany przez odniesienie do funkcji?

Nie, ponieważ użytkownik uzyskuje dostęp do surowego wskaźnika, a następnie przekazuje go. Chcesz zrobić coś podobnego do tego:

f(shared_ptr<object> o){ 
    //do something 
} 

int main(){ 
    shared_ptr<object> p (new object()); 
    f(p); 
} 
-1

Po pierwsze, z punktu widzenia funkcjonalności odniesienia w C++ są dokładnie takie same jak wskaźniki. Powodem, dla którego zostali oni dodani do tego języka, było spowodowanie, by składnia przeciążenia operatora była bardziej naturalna. (Na przykład, aby umożliwić zapisanie a + b zamiast & a + & b)

Twoje próbki kodu C i C++ nie są absolutnie równoważne. C wersja Twojego kodu C++ byłoby:

f(object *p){ 
    //do something 
} 

int main(){ 
    object o; 
    object_constructor(&o); 
    f(&o); 
    object_destructor(&o); 
} 

W rzeczywistości, jest to rodzaj kodu, że kompilator C++ będzie koncepcyjnie generują.

W odniesieniu do drugiego pytania: Tak, to jest poprawny sposób wywoływania funkcji f. Współużytkowany licznik wskaźnika nie zostanie zwiększony. Rzeczywisty wskaźnik do obiektu zostanie przekazany, tak jakby nie korzystałeś z shared_ptr. Jest jednak bezpieczny, o ile f nie robi nic zabawnego. Pamiętaj tylko, że to samo dzieje się tak, jakby parametr f wziął wskaźnik zamiast odniesienia. Jedyną różnicą jest to, że kompilator automagicznie przekazuje adres zmiennej bez konieczności jawnego korzystania z operatora &.

Ja osobiście nie lubię przekazywać zmiennych przez odniesienie (przekazywanie przez odniesienie do stałej jest jednak w porządku). Zamiast tego wolę używać wskaźnika, ponieważ dzięki niemu w witrynie wywołania jest lepiej widoczne, że funkcja, do której dzwonimy, może potencjalnie zmodyfikować jej argument (ponieważ symbol & jest widoczny na stronie połączenia).

Peace

+2

Przepraszamy, ale "odniesienia w C++ są dokładnie takie same jak wskaźniki" jest błędne. Być może jest to po prostu styl, ale myślę, że większość programistów C++ zgodzi się, że przekazywanie wskaźników zamiast referencji jest głupie. Teraz musisz ciągle sprawdzać wartość zerową. Referencje są bardziej naturalne. – GManNickG

1
f(object& o){ 
    //do something 
} 

int main(){ 
    shared_ptr<object> p (new object()); 
    f(*p); 
} 

Czy wspólny wskaźnik być zwiększany gdy jej przedmiotem jest przekazywane przez referencję do funkcji?

W powyższym kodzie - nie. p będzie miał swój licznik odniesienia równy 1 przez cały czas. Możesz to sprawdzić w debugerze. Współczynnik odniesienia shared_ptr zlicza liczbę instancji shared_ptr, które wskazują ten sam obiekt, nie śledzi referencji tworzonych przez wywołanie operatora *(). I nie musi - ponieważ p ma gwarancję na życie do końca zakresu, a wywołanie funkcji jest w tym samym zakresie (lub głębiej) p będzie tam podczas całego połączenia do f (). Więc wszystko jest w porządku.

... chyba w f wziąć adres o i przechowywać gdzieś, że będzie trwać po f zwrotów. Tego należy unikać na wszelkie sposoby - należy przekazać shared_ptr, jeśli trzeba to zrobić.

Powiązane problemy