簡體   English   中英

為什么SGI STL不使用復制和交換習慣用法?

[英]Why SGI STL don't use the copy-and-swap idiom?

我最近在StackOverflow上讀到了關於什么是復制和交換習語的答案 並且知道復制和交換習語可以

避免代碼重復,並提供強大的異常保證。

但是,當我查看SGI STL deque 實現時 ,我發現它沒有使用這個成語。 我想知道為什么不,如果成語在某種程度上像一個“最佳實踐”?

  deque& operator= (const deque& __x) {
    const size_type __len = size();
    if (&__x != this) {
      if (__len >= __x.size())
        erase(copy(__x.begin(), __x.end(), _M_start), _M_finish);
      else {
        const_iterator __mid = __x.begin() + difference_type(__len);
        copy(__x.begin(), __mid, _M_start);
        insert(_M_finish, __mid, __x.end());
      }
    }
    return *this;
  }       

您顯示的代碼不會重新分配內存,除非容器需要增長,這可能是一個顯着的節省。 復制和交換總是分配內存來執行復制,然后釋放現有元素的內存。

考慮一個deque<vector<int>> ,其中deque<vector<int>>的現有向量成員具有大容量。

deque<vector<int>> d(2);
d[0].reserve(100);
d[1].reserve(100);

使用SGI STL實現,為每個元素分配會保留該容量,因此如果向量需要增長,則可以在不分配任何內容的情況下執行此操作:

d = deque<vector<int>>(2);
assert(d[0].capacity() >= 100);
assert(d[1].capacity() >= 100);
d[0].push_back(42);  // does not cause an allocation

復制和交換將使用沒有備用容量的新元素替換現有成員,因此上面的斷言將失敗,並且push_back將需要分配內存。 這會浪費時間解除分配和重新分配,而不是使用已經存在的完美記憶。

復制和交換是一種非常容易獲得異常安全性和正確性的便捷方式,但不一定盡可能高效。 在像STL或C ++標准庫這樣的代碼中,您不希望為了稍微簡單的實現而犧牲效率,並且這些代碼通常應該由能夠通過“艱難的方式”實現異常安全的專家編寫。 “不僅僅是最方便的方式。

這個成語是一種提供強有力的異常保證的簡單方法,因此除非你有充分的理由不做,否則這是一個好的事情意義上的“最佳實踐”。

但是,它有一個成本:必須創建和銷毀第二個對象。 這可能很昂貴,如果這涉及大量內存分配,可能會使峰值內存使用量增加到必要的程度。 如果這是一個問題,或者你正在編寫像這樣的通用庫,你應該找到其他方法來復制對象而不創建臨時對象。 與使用簡單的習語相比,異常安全需要更多的關注。

雖然復制和交換是最佳實踐,但在某些情況下可能會帶來效率損失。 在這種特定情況下,代碼利用了這樣的事實:如果被分配的向量已經具有足夠的可用內存,則可以復制這些值而無需進行額外的內存分配。

我想在這種情況下這樣做是為了避免多余的重新分配:復制和交換將需要分配副本(因此在某個時刻進行雙重存儲),然后釋放所有雙端隊列的內存。 僅當copy-from較大且僅需要差異時,此代碼才會分配。

這實際上適用於deque而不是vector - 在那里如何實現vector :: operator =?

而且這可能是在成語變得流行之前寫的。 即使是現在它也沒有被普遍接受。

std::deque<T>::operator=(const std::deque<T>&)應該提供基本的異常保證 - 即在異常的情況下容器保持有效狀態,不是強有力的保證 - 這會爭論使用復制/交換。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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