Myślę, że to trochę subiektywne; Nie jestem pewien, czy opinia będzie jednomyślna (widziałem wiele fragmentów kodu, w których zwracane są odwołania).
Zgodnie z komentarzem do tego pytania, które właśnie zadałem, dotyczące inicjowania referencji , zwracanie referencji może być złe, ponieważ [jak rozumiem] ułatwia to pominięcie usunięcia, co może prowadzić do wycieków pamięci.
Martwi mnie to, bo podążałem za przykładami (chyba, że coś sobie wyobrażam) i robiłem to w kilku uczciwych miejscach ... Czy źle zrozumiałem? Czy to jest złe? Jeśli tak, to jak złe?
Wydaje mi się, że z powodu mojego mieszanego zestawu wskaźników i odniesień, w połączeniu z faktem, że jestem nowy w C ++, oraz całkowitym zamieszaniem co do tego, kiedy użyć, gdy moje aplikacje muszą być piekłem pamięci ...
Rozumiem również, że używanie inteligentnych / współdzielonych wskaźników jest ogólnie akceptowane jako najlepszy sposób uniknięcia wycieków pamięci.
Odpowiedzi:
Zasadniczo zwracanie referencji jest całkowicie normalne i odbywa się przez cały czas.
Jeśli masz na myśli:
To wszelkiego rodzaju zło. Przydział stosu
i
zniknie, a ty nie odnosisz się do niczego. To też jest złe:Ponieważ teraz klient musi w końcu zrobić coś dziwnego:
Zauważ, że odniesienia do wartości są nadal tylko odniesieniami, więc wszystkie złe aplikacje pozostają takie same.
Jeśli chcesz przydzielić coś, co wykracza poza zakres funkcji, użyj inteligentnego wskaźnika (lub ogólnie kontenera):
A teraz klient przechowuje inteligentny wskaźnik:
Referencje są również w porządku, aby uzyskać dostęp do rzeczy, o których wiesz, że całe życie jest otwarte na wyższym poziomie, np .:
Wiemy tutaj, że można odwoływać się do odwołania,
i_
ponieważ to, co nas wzywa, zarządza czasem życia instancji klasy, więci_
będzie żyła przynajmniej tak długo.I oczywiście nie ma nic złego w samym tylko:
Jeśli czas życia należy do dzwoniącego, a ty po prostu obliczasz wartość.
Podsumowanie: można zwrócić referencję, jeśli czas życia obiektu nie skończy się po wywołaniu.
źródło
return new int
.Nie, nie, tysiąc razy nie.
To, co jest złem, odnosi się do dynamicznie przydzielanego obiektu i traci oryginalny wskaźnik. Kiedy jesteś
new
przedmiotem, zobowiązujesz się mieć gwarancjędelete
.Ale spójrz np. Na
operator<<
: to musi zwrócić referencję, lubnie zadziała.
źródło
Powinieneś zwrócić odniesienie do istniejącego obiektu, który nie odchodzi natychmiast i gdzie nie zamierzasz przenosić prawa własności.
Nigdy nie zwracaj odwołania do zmiennej lokalnej lub innej takiej, ponieważ nie będzie tam odniesienia.
Możesz zwrócić odwołanie do czegoś niezależnego od funkcji, którego nie oczekujesz, że funkcja wywołująca przejmie odpowiedzialność za usunięcie. Dotyczy to typowej
operator[]
funkcji.Jeśli coś tworzysz, powinieneś zwrócić wartość lub wskaźnik (zwykły lub inteligentny). Możesz swobodnie zwrócić wartość, ponieważ przechodzi ona do zmiennej lub wyrażenia w funkcji wywołującej. Nigdy nie zwracaj wskaźnika do zmiennej lokalnej, ponieważ ona zniknie.
źródło
Uważam, że odpowiedzi nie są satysfakcjonujące, więc dodam dwa centy.
Przeanalizujmy następujące przypadki:
Błędne użycie
To oczywiście błąd
Zastosowanie ze zmiennymi statycznymi
Ma to rację, ponieważ zmienne statyczne istnieją przez cały okres istnienia programu.
Jest to również dość powszechne przy wdrażaniu wzorca Singleton
Stosowanie:
Operatorzy
Standardowe kontenery biblioteczne w dużym stopniu zależą na przykład od operatorów, które zwracają referencje
może być użyty w następujący sposób
Szybki dostęp do danych wewnętrznych
Są chwile, kiedy & może być wykorzystany do szybkiego dostępu do danych wewnętrznych
z użyciem:
JEDNAK może to prowadzić do takich pułapek:
źródło
true
If((a*b) == (c*d))
Container::data()
implementacja powinna brzmiećreturn m_data;
To nie jest złe. Podobnie jak wiele rzeczy w C ++, jest dobrze, jeśli jest używany poprawnie, ale istnieje wiele pułapek, o których powinieneś pamiętać podczas korzystania z niego (np. Zwracanie odwołania do zmiennej lokalnej).
Są dobre rzeczy, które można z nim osiągnąć (np. Map [name] = "hello world")
źródło
map[name] = "hello world"
?HashMap<String,Integer>
w Javie? : PNie prawda. Zwrócenie referencji nie oznacza semantyki własności. To dlatego, że robisz to:
... nie oznacza, że posiadasz teraz pamięć, o której mowa w v;
Jest to jednak okropny kod:
Jeśli robisz coś takiego, ponieważ „nie potrzebujesz wskaźnika w tej instancji”, to: 1) po prostu odłóż wskaźnik, jeśli potrzebujesz odniesienia, i 2) w końcu będziesz potrzebować wskaźnika, ponieważ musisz dopasować nowy z usunięciem, a do wywołania usunięcia potrzebny jest wskaźnik.
źródło
Istnieją dwa przypadki:
const reference - dobry pomysł, czasem, szczególnie dla ciężkich obiektów lub klas proxy, optymalizacja kompilatora
non-const reference - zły pomysł, czasami psuje enkapsulacje
Oba mają ten sam problem - mogą potencjalnie wskazywać na zniszczony obiekt ...
Polecam używanie inteligentnych wskaźników w wielu sytuacjach, w których musisz zwrócić referencję / wskaźnik.
Zwróć również uwagę na następujące kwestie:
Istnieje formalna reguła - Standard C ++ (sekcja 13.3.3.1.4, jeśli jesteś zainteresowany) stwierdza, że tymczasowe może być powiązane tylko z odwołaniem do stałej - jeśli spróbujesz użyć odwołania do stałej, kompilator musi oznaczyć to jako błąd.
źródło
Nie tylko nie jest zły, ale czasami jest niezbędny. Na przykład niemożliwe byłoby zaimplementowanie operatora [] std :: vector bez użycia zwracanej wartości referencyjnej.
źródło
operator[]
kontener bez użycia odwołania ... istd::vector<bool>
robi to. (I w ten sposób powstaje prawdziwy bałagan)::std::vector<bool>
wspomniano).std::vector<T>
kodu szablonu jest zepsute, jeśliT
może byćbool
, ponieważstd::vector<bool>
ma inne zachowanie niż inne instancje. Jest to przydatne, ale powinno się nadać mu własną nazwę, a nie specjalizacjęstd::vector
.Dodatek do zaakceptowanej odpowiedzi:
Twierdziłbym, że ten przykład jest nie w porządku i należy go w miarę możliwości unikać. Dlaczego? Bardzo łatwo jest uzyskać zwisające odniesienie .
Aby zilustrować tę kwestię przykładem:
wejście do strefy zagrożenia:
źródło
referencja powrotu jest zwykle używana w przypadku przeciążenia operatora w C ++ dla dużych obiektów, ponieważ zwracanie wartości wymaga operacji kopiowania. (w przeciążeniu peratora zwykle nie używamy wskaźnika jako wartości zwracanej)
Ale odwołanie zwrotne może powodować problem z alokacją pamięci. Ponieważ odwołanie do wyniku zostanie przekazane z funkcji jako odniesienie do wartości zwracanej, wartość zwracana nie może być zmienną automatyczną.
jeśli chcesz użyć zwracanej wartości, możesz użyć bufora obiektu statycznego. na przykład
w ten sposób możesz bezpiecznie korzystać ze zwracanego odwołania.
Ale zawsze możesz użyć wskaźnika zamiast odwołania do zwracania wartości w functiong.
źródło
myślę, że używanie referencji jako wartości zwracanej przez funkcję jest znacznie prostsze niż używanie wskaźnika jako wartości zwracanej przez funkcję. Po drugie, zawsze byłoby bezpiecznie używać zmiennej statycznej, do której odnoszą się wartości zwracane.
źródło
Najlepiej jest utworzyć obiekt i przekazać go jako parametr referencyjny / wskaźnikowy do funkcji, która przydziela tę zmienną.
Przydzielanie obiektu w funkcji i zwracanie go jako odwołania lub wskaźnika (wskaźnik jest jednak bezpieczniejszy) jest złym pomysłem ze względu na zwolnienie pamięci na końcu bloku funkcyjnego.
źródło
Funkcja getPtr może uzyskać dostęp do pamięci dynamicznej po usunięciu, a nawet zerowego obiektu. Co może powodować wyjątki złego dostępu. Zamiast tego należy wprowadzić getter i setter, a przed zwrotem sprawdzić rozmiar.
źródło
Funkcja jako lvalue (czyli zwracanie odwołań nie stałych) powinna zostać usunięta z C ++. To jest wyjątkowo nieintuicyjne. Scott Meyers chciał min () z tym zachowaniem.
co nie jest tak naprawdę poprawą
To drugie ma nawet większy sens.
Zdaję sobie sprawę, że funkcja jako wartość jest ważna dla strumieni w stylu C ++, ale warto zauważyć, że strumienie w stylu C ++ są okropne. Nie jestem jedynym, który tak myśli ... jak pamiętam Alexandrescu miał duży artykuł na temat tego, jak robić lepiej, i uważam, że boost próbował również stworzyć lepszą metodę bezpiecznych I / O.
źródło
vector::operator[]
na przykład. Wolisz pisaćv.setAt(i, x)
czyv[i] = x
? Ten ostatni jest lepszy od FAR.v.setAt(i, x)
zawsze. Jest o wiele lepszy.Natknąłem się na prawdziwy problem, w którym to rzeczywiście było złe. Zasadniczo programista zwrócił odwołanie do obiektu w wektorze. To było złe!!!
Pełne szczegóły, o których pisałem w Janurary: http://developer-resource.blogspot.com/2009/01/pros-and-cons-of-returing-references.html
źródło
O okropnym kodzie:
Rzeczywiście wskaźnik pamięci utracony po powrocie. Ale jeśli używasz share_ptr w ten sposób:
Pamięć nie zostanie utracona po powrocie i zostanie zwolniona po przypisaniu.
źródło