簡體   English   中英

為什么 std::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 popconst 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM