Dlaczego std:: queue:: pop nie zwraca wartości.?

Przejrzałem tę Stronę ale nie jestem w stanie uzyskać tego samego powodu . Tam jest wspomniane, że

" rozsądniej jest, aby nie zwracała żadnej wartości i wymagała klienci, którzy używają funkcji front() do sprawdzenia wartości z przodu kolejki"

Ale sprawdzenie elementu z front() również wymagało 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 zostaną utworzone na RHS które zostaną przypisane do wyniku, a w przypadku jeśli zostanie zwrócona przez odniesienie, wynik zostanie unieważniony po operacji pop * /

result = myqueue.front();  //result.
std::cout << ' ' << result;
myqueue.pop();

W piątej linii cout obiekt najpierw tworzy kopię myqueue.front() następnie przypisuje to do result. Więc jaka jest różnica, funkcja pop mogła zrobić to samo.

 135
Author: cbinder, 2014-07-30

7 answers

Więc jaka jest różnica, funkcja pop mogła zrobić to samo.

Rzeczywiście mógł zrobić to samo. Powodem, dla którego tego nie zrobił, jest to, że pop, który zwrócił element Popp, jest niebezpieczny w obecności WYJĄTKÓW (konieczność zwracania przez wartość i tworzenie kopii).

Rozważ ten scenariusz (z naiwną/wymyśloną implementacją pop, aby zilustrować mój punkt widzenia):

template<class T>
class queue {
    T* elements;
    std::size_t top_position;
    // stuff here
    T pop()
    {
        auto x = elements[top_position];
        // TODO: call destructor for elements[top_position] here
        --top_position;  // alter queue state here
        return x;        // calls T(const T&) which may throw
    }

Jeśli Konstruktor kopiujący T rzuca po powrocie, masz już zmieniono stan kolejki (top_position w mojej naiwnej implementacji) i element jest usuwany z kolejki (a nie zwracany). Dla wszystkich celów (bez względu na sposób przechwycenia wyjątku w kodzie klienta) element na górze kolejki jest tracony.

Ta implementacja jest również nieefektywna w przypadku, gdy nie jest potrzebna wartość popped (tzn. tworzy kopię elementu, którego nikt nie będzie używał).

To może być realizowane bezpiecznie i skutecznie, z dwóch oddzielnych operacje (void pop i const T& front()).

 112
Author: utnapistim,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 12:06:57

Strona, którą podlinkowałeś odpowiada na twoje pytanie.

Zacytuję całą sekcję:

Można się zastanawiać, dlaczego pop() zwraca void, zamiast value_type. To znaczy, dlaczego trzeba użyć funkcji front() i pop (), aby sprawdzić i usunąć element z przodu kolejki, zamiast łączyć te dwa elementy w jedną funkcję członkowską? W rzeczywistości istnieje dobry powód dla tego projektu. Jeśli pop() zwróci element przedni, będzie musiał zwracać wartość, a nie referencję: return by reference utworzy zwisający wskaźnik. Zwracanie przez wartość jest jednak nieefektywne: wymaga co najmniej jednego nadmiarowego wywołania konstruktora kopiującego. Ponieważ nie jest możliwe, aby pop() zwracała wartość w taki sposób, aby była zarówno efektywna, jak i poprawna, rozsądniejsze jest zwrócenie żadnej wartości i wymaganie od klientów użycia funkcji front() do sprawdzenia wartości z przodu kolejki.

C++ został zaprojektowany z myślą o wydajności, nad liczbą wierszy kodu programista musi pisać.

 37
Author: BPF2010,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-28 10:49:04

Pop nie może zwrócić odniesienia do wartości, która jest usuwana, ponieważ jest usuwana ze struktury danych, więc do czego powinno się odnosić odniesienie? Może zwracać wartość, ale co, jeśli wynik pop nie jest nigdzie zapisywany? Wtedy czas jest marnowany na niepotrzebne kopiowanie wartości.

 5
Author: Neil Kirk,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 11:37:58

W obecnej implementacji jest to ważne:

int &result = myqueue.front();
std::cout << result;
myqueue.pop();

Jeśli pop zwróci referencję, w ten sposób:

value_type& pop();

Następnie poniższy kod może ulec awarii, ponieważ odniesienie nie jest już ważne:

int &result = myqueue.pop();
std::cout << result;

Z drugiej strony, jeśli zwróci wartość bezpośrednio:

value_type pop();

Wtedy trzeba by zrobić kopię, aby ten kod zadziałał, co jest mniej efektywne:

int result = myqueue.pop();
std::cout << result;
 3
Author: Jan Rüegg,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 12:06:36

Począwszy od C++11 możliwe byłoby archiwizowanie pożądanych zachowań za pomocą semantyki move. Jak pop_and_move. Tak więc Konstruktor kopiujący nie zostanie wywołany, a wydajność będzie zależeć tylko od konstruktora move.

 1
Author: Vyacheslav Putsenko,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2019-05-25 01:44:04

Możesz to zrobić:

std::cout << ' ' << myqueue.front();

Lub, jeśli chcesz mieć wartość w zmiennej, użyj referencji:

const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;

Obok: sformułowanie "bardziej rozsądne" jest subiektywną formą "przyjrzeliśmy się wzorcom użytkowania i stwierdziliśmy większą potrzebę podziału". (Zapewniam: język C++ nie rozwija się lekko...)

 0
Author: xtofl,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-07-30 11:37:38

Myślę, że najlepszym rozwiązaniem byłoby dodanie czegoś w rodzaju

std::queue::pop_and_store(value_type& value);

Gdzie wartość otrzyma wartość popped.

Zaletą jest to, że można go zaimplementować za pomocą operatora przyporządkowania ruchu, podczas gdy użycie front + pop zrobi kopię.

 0
Author: Masse Nicolas,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-28 19:27:09