Przeszedłem przez tę stronę, ale nie mogę znaleźć powodu tego samego. Tam jest o tym mowa
„bardziej rozsądne jest, aby nie zwracał żadnej wartości i wymagał od klientów używania metody front () w celu sprawdzenia wartości na początku kolejki”
Ale sprawdzenie elementu z front () wymagało również skopiowania tego elementu w lvalue. Na przykład w tym segmencie kodu
std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
/ * tutaj tymczasowe zostanie utworzone na RHS, które zostanie przypisane do wyniku, aw przypadku, gdy zwróci przez odniesienie, wynik zostanie unieważniony po operacji pop * /
result = myqueue.front(); //result.
std::cout << ' ' << result;
myqueue.pop();
w piątej linii obiekt cout najpierw tworzy kopię myqueue.front (), a następnie przypisuje ją do wyniku. Jaka jest różnica, funkcja pop mogłaby zrobić to samo.
void std::queue::pop();
.).front()
również wymagało skopiowania tego elementu w lwartości” - nie, nie jest.front
zwraca odniesienie, a nie wartość. Możesz sprawdzić wartość, do której się odnosi, bez kopiowania jej.pop()
. Jeśli używasz,std::queue<T, std::list<T>>
nie ma obaw, że podane odniesieniefront()
zostanie unieważnione przezpush()
. Ale musisz znać swój wzorzec użytkowania i dokumentować swoje ograniczenia.Odpowiedzi:
Rzeczywiście mógł zrobić to samo. Powodem tego jest to, że pop, który zwrócił popped element, jest niebezpieczny w obecności wyjątków (konieczność zwracania wartości, a tym samym tworzenie kopii).
Rozważmy następujący scenariusz (z naiwną / zmyśloną implementacją pop, aby zilustrować mój punkt widzenia):
Jeśli konstruktor kopiujący T zgłasza po powrocie, to już zmieniłeś stan kolejki (
top_position
w mojej naiwnej implementacji) i element jest usuwany z kolejki (i nie zwracany). W każdym przypadku (bez względu na to, w jaki sposób wyłapiesz wyjątek w kodzie klienta) element na początku kolejki jest tracony.Ta implementacja jest również nieefektywna w przypadku, gdy nie potrzebujesz wartości popped (tj. Tworzy kopię elementu, którego nikt nie będzie używał).
Można to wdrożyć bezpiecznie i wydajnie za pomocą dwóch oddzielnych operacji (
void pop
iconst T& front()
).źródło
pop
? to jest dość sprzeczne z intuicją. Można by go nazwaćdrop
, a wtedy jest jasne dla wszystkich, że niepop
nic nie zwróciłem . Zobacz na przykład na wikipedii .Strona, do której masz łącze, odpowiada na Twoje pytanie.
Cytując cały odpowiedni dział:
C ++ został zaprojektowany z myślą o wydajności, biorąc pod uwagę liczbę linii kodu, które musi napisać programista.
źródło
pop
która zwraca wartość.pop nie może zwrócić odwołania do usuwanej wartości, ponieważ jest ona usuwana ze struktury danych, więc do czego powinno odnosić się odwołanie? Może zwracać wartość, ale co, jeśli wynik pop nie jest nigdzie przechowywany? Wtedy marnuje się czas na niepotrzebne kopiowanie wartości.
źródło
pop
zwraca, a czynność zwracania może spowodować wyjątek. Musiałby oczywiście usunąć element, zanim go zwróci, a następnie, jeśli coś wyrzuci, element może zostać nieodwracalnie utracony.value_type
ma konstruktor przenoszenia nothrow, ale interfejs kolejki będzie wtedy inny w zależności od typu obiektu, który w nim przechowujesz, co nie byłoby pomocne.Przy obecnej implementacji jest to ważne:
Jeśli pop zwróciłby odwołanie, takie jak to:
Następnie następujący kod może ulec awarii, ponieważ odwołanie jest już nieprawidłowe:
Z drugiej strony, gdyby zwrócił wartość bezpośrednio:
Następnie musisz zrobić kopię, aby ten kod działał, co jest mniej wydajne:
źródło
Począwszy od C ++ 11 możliwe byłoby zarchiwizowanie żądanego zachowania przy użyciu semantyki przenoszenia. Lubię
pop_and_move
. Więc konstruktor kopiujący nie zostanie wywołany, a wydajność będzie zależeć tylko od konstruktora przenoszenia.źródło
pop
wyjątków bezpiecznymi.Możesz to całkowicie zrobić:
Lub, jeśli chcesz, aby wartość była zawarta w zmiennej, użyj odwołania:
Poza tym: sformułowanie „bardziej sensowne” jest subiektywną formą stwierdzenia, że „przyjrzeliśmy się wzorcom użycia i stwierdziliśmy większą potrzebę podziału”. (Zapewniamy: język C ++ nie rozwija się lekko ...)
źródło
Myślę, że najlepszym rozwiązaniem byłoby dodanie czegoś takiego
gdzie value otrzyma wartość popped.
Zaletą jest to, że można go zaimplementować za pomocą operatora przypisania ruchu, podczas gdy użycie front + pop spowoduje utworzenie kopii.
źródło