2016-11-25 65 views
3

例如,來自的std ::雙端隊列::運算=在C++參考:
(1)複印分配(常量的std ::雙端隊列&其他)
分配器感知容器分配如何實現?

替換內容與其他的內容的副本。
如果 std :: allocator_traits :: propagate_on_container_copy_assignment()爲 爲true,則目標分配器將被替換爲源 分配器的副本。如果目標分配器和源分配器不相比 相等,則使用目標(* this)分配器來釋放內存,然後使用其他分配器在複製 元素之前分配它。

如果this->get_allocator() == other.get_allocator(),我可以簡單地破壞,並在需要解除分配this'元素,或分配,如果需要,構造元件,或者如果需要的話從other的元素複製分配給*this
但是,如果不是?上面的報價是否意味着我不能複製 - 分配元素,因此我必須先使用this->get_allocator()銷燬和釋放所有元素,然後使用other.get_allocator()分配和構造元素?
但是,如果是這樣的話,爲什麼我應該使用other.get_allocator()進行分配?
以後會不會導致一些運行時錯誤,因爲this不會正確釋放內存?

(2)移動分配(標準::雙端隊列& &其他)

替換內容與其他 使用移動語義的(即,在其它的數據是從其它移動進入 這個容器)。之後其他人處於有效但未明確的狀態。 如果 std :: allocator_traits :: propagate_on_container_move_assignment() 爲true,則目標分配器將被替換爲源 分配器的副本。如果它是假的,並且源和目標分配器的比較不等於 ,則目標無法獲取源內存的所有權,並且必須單獨移動 - 分配每個元素,根據需要使用其自己的分配程序分配額外的內存。在任何情況下,原來存在於*的所有 元素都將被銷燬,或者通過元素移動賦值來替換 。

如果this->get_allocator() == other.get_allocator(),這是一件容易的事。
但是,如果沒有,上面的問題也會出現,除非在這種情況下使用移動分配。

在這兩種情況下,我還有一個問題。
如果這些元素既不能被複制分配也不能被移動分配,那麼可以銷燬它並從其他構造中構建它們嗎?如果是,我應該使用其分配器?

回答

5

甲POCCA(傳播在容器拷貝賦值)分配器是拷貝指定爲容器的拷貝分配的一部分。同樣,POCMA分配器在分配容器的移動時移動分配。

請問上述報價意味着我不能複製指定的元素,所以我必須銷燬先回收的所有元素,使用this->get_allocator(),然後分配和構建元素,採用other.get_allocator()

正確。

但是,如果是這樣的話,爲什麼我應該使用other.get_allocator進行分配?以後會不會導致一些運行時錯誤,因爲this->get_allocator()不會正確釋放內存?

由於分配傳播分配:分配後,this->get_allocator()other.get_allocator()一個副本,因此它可以安全地釋放內存由它分配。

如果this->get_allocator() == other.get_allocator(),這是一件容易的事。但是,如果沒有,上面的問題也會出現,除非在這種情況下使用移動分配。

其實,這是完全不同的。使用POCMA分配器移動任務很簡單:您銷燬*this中的所有元素,釋放內存,然後掠取內存和分配器other

,其中容器移動分配有訴諸元素明智之舉分配的唯一情況/建築是當你有一個非POCMA分配器和分配器比較不等。在這種情況下,所有的分配和構造都由this->get_allocator()完成,因爲您不會傳播任何東西。

在這兩種情況下,我有一個額外的問題。如果元素既不能被複制分配也不能被移動分配,是可以銷燬它並從其他構造中構建的?如果是,我應該使用其分配器?

使用它最初與構造的分配器毀壞。使用它將被銷燬的分配器來構造它。換句話說,如果您正在傳播分配器,那麼使用目標分配器銷燬它並使用源分配器進行構造。

+0

什麼非POCCA分配器?我是否必須隨時使用'this-> get_allocator()'? –

+1

嗯,是的,如果你需要分配。 –

3

我回答我的問題,以顯示我得到了什麼。 --Dannyu NDOS,2017年1月16日

在副本

無論是或移動作業,其行爲取決於兩個條件:
是分配器比較平等的嗎? (即,是源分配器能夠破壞和解除分配所述目標容器的要素是什麼?)
2.不源的分配器繁殖容器分配期間(=被分配到目標)?

用於複製作業:
A.如果分配器比較相等:
將元素直接複製分配給元素可以安全地完成。
由於分配器已經比較相等,分配器是否傳播並不重要。如果任何元素需要被構造或銷燬,那麼它的分配者是否也是如此。
B.如果分配器不相等:
B.a.如果分配器不傳播:
直接向元素複製元素賦值可以安全完成,但是如果需要構造或銷燬任何元素,則源分配器必須執行此操作,因爲只有它可以銷燬目標容器的元素。
B.b.如果分配器傳播:
首先,目標分配器必須刪除和釋放所有目標容器的元素。
然後分配器傳播,然後源分配器分配並複製構造所有源容器的元素。

對於移動分配:
A.如果分配器比較相等:
目標容器擦除其所有元素,然後取源容器的元素的所有權。這需要O(1)次。
B.如果分配器不相等:
B.a.如果分配器不傳播:
直接將元素分配給元素可以安全地完成,但是如果需要構造或銷燬任何元素,則源分配器必須執行此操作,因爲只有它可以銷燬源容器的元素。這需要O(n)時間。分配後源容器必須處於有效狀態。
B.b.如果分配器傳播:
首先,目標分配器必須刪除和釋放所有目標容器的元素。
然後分配器傳播,然後源分配器分配並移動構造所有源容器的元素。這需要O(n)時間。分配後源容器必須處於有效狀態。

在源代碼中,給出alloc是容器的分配器,Alloc是它的類型,它們一般這樣寫的:

/*container*/ &operator = (const /*container*/ &other) { 
    if (std::allocator_traits<Alloc>::propagate_on_container_copy_assignment::value && alloc != other.alloc) { 
     clear(); 
     alloc = other.alloc; 
     // directly copy-constructs the elements. 
    } else { 
     // directly copy-assigns the elements. 
     // alloc does all allocation, construction, destruction, and deallocation as needed. 
    } 
    return *this; 
} 
/*container*/ &operator = (/*container*/ &&other) 
noexcept(std::allocator_traits<Alloc>::is_always_equal::value) { 
    if (alloc == other.alloc) { 
     clear(); 
     // *this takes ownership of other's elements. 
    } else if (std::allocator_traits<Alloc>::propagate_on_container_move_assignment::value) { 
     clear(); 
     alloc = other.alloc; 
     // directly move-constructs the elements. 
    } else { 
     // directly move-assigns the elements. 
     // alloc does all allocation, construction, destruction, and deallocation as needed. 
    } 
    // the source container is made valid, if needed. 
    return *this; 
}