![](/img/trans.png)
[英]Why is return value of queue:front() valid after queue::pop()
[英]Why doesn't std::queue::pop return value.?
我瀏覽了這個頁面,但我無法得到同樣的原因。 那里提到
“更明智的是它根本不返回任何值並要求客戶端使用 front() 來檢查隊列前面的值”
但是從 front() 中檢查元素也需要將該元素復制到左值中。 例如在這個代碼段中
std::queue<int> myqueue;
int myint;
int result;
std::cin >> myint;
myqueue.push (myint);
/* here temporary will be created on RHS which will be assigned to
result, and in case if returns by reference then result will be
rendered invalid after pop operation */
result = myqueue.front(); //result.
std::cout << ' ' << result;
myqueue.pop();
在第五行cout object 首先創建一個 myqueue.front() 的副本,然后將其分配給結果。 那么,有什么區別,pop function 可以做同樣的事情。
因此,有什么區別,pop函數可以完成相同的操作。
它確實可以做同樣的事情。 之所以沒有這樣做,是因為在存在異常的情況下,返回popped元素的pop是不安全的(必須按值返回並因此創建一個副本)。
考慮這種情況(使用天真的/虛構的流行實現,以闡明我的觀點):
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
}
如果T的副本構造函數在返回時拋出,則您已經更改了隊列的狀態(在我的朴素實現中為top_position
),並且從隊列中刪除了該元素(並且不返回)。 出於所有意圖和目的(無論如何在客戶端代碼中捕獲異常),隊列頂部的元素都會丟失。
如果您不需要彈出的值(即,它會創建一個沒人使用的元素的副本),則此實現的效率也很低。
這可以通過兩個單獨的操作( void pop
和const T& front()
)安全有效地實現。
您鏈接到的頁面回答了您的問題。
引用整個相關部分:
有人可能想知道為什么pop()返回void而不是value_type。 也就是說,為什么必須使用front()和pop()來檢查並刪除隊列最前面的元素,而不是將兩者合並為一個成員函數? 實際上,這種設計是有充分理由的。 如果pop()返回front元素,則必須按值而不是按引用返回:按引用返回將創建一個懸空指針。 但是,按值返回效率低下:它涉及至少一個冗余副本構造函數調用。 由於pop()不可能以有效且正確的方式返回值,因此更明智的做法是根本不返回任何值,並要求客戶端使用front()來檢查值隊列的最前面。
C ++的設計考慮了效率,在程序員必須編寫的代碼行數之上。
由於無法從數據結構中刪除該數據,因此pop無法返回對該已刪除的值的引用,因此該引用應引用什么? 它可以按值返回,但是如果pop的結果沒有存儲在任何地方怎么辦? 然后浪費時間不必要地復制該值。
對於當前的實現,這是有效的:
int &result = myqueue.front();
std::cout << result;
myqueue.pop();
如果pop將返回引用,如下所示:
value_type& pop();
然后,以下代碼可能會崩潰,因為該引用不再有效:
int &result = myqueue.pop();
std::cout << result;
另一方面,如果它將直接返回一個值:
value_type pop();
然后,您需要為該代碼工作而制作一個副本,效率較低:
int result = myqueue.pop();
std::cout << result;
從C ++ 11開始,可以使用move語義來歸檔所需的行為。 就像pop_and_move
一樣。 因此不會調用復制構造函數,而性能將僅取決於move構造函數。
您可以完全做到這一點:
std::cout << ' ' << myqueue.front();
或者,如果要在變量中使用值,請使用引用:
const auto &result = myqueue.front();
if (result > whatever) do_whatever();
std::cout << ' ' << result;
緊隨其后的是:“更明智”一詞是“我們研究了使用模式並發現了更多分割需求”的主觀形式。 (請放心:C ++語言發展緩慢)。
我認為最好的解決方案是添加類似
std::queue::pop_and_store(value_type& value);
其中value將接收彈出的值。
優點是可以使用移動分配運算符來實現,而使用front + pop可以進行復制。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.