2016-11-25 10 views
3

Например, из стандов :: Deque :: оператора = в C++ Reference:
(1) Копия Назначение(Const станда :: Deque & друг)
Как реализовано назначение контейнера с поддержкой распределителя?

Заменяет содержимое с копией содержимого другого.
Если std :: allocator_traits :: propagate_on_container_copy_assignment() is true, целевой распределитель заменяется копией источника распределителя. Если целевые и исходные распределители не сравнивают равным, целевой (* этот) распределитель используется для освобождения памяти, , тогда другой распределитель используется для распределения его перед копированием элементов .

Если this->get_allocator() == other.get_allocator(), я могу просто уничтожить и освободить this 'элементы, если это необходимо, или выделить и построить элементы, если это необходимо, или копирования назначить элементы из other в *this при необходимости.
А что, если нет? Является ли цитата выше, что я не могу копировать-присваивать элементы, поэтому мне нужно сначала уничтожить и удалить все элементы, используя this->get_allocator(), а затем выделить и построить элементы, используя other.get_allocator()?
Но если это так, почему я должен использовать other.get_allocator() для распределения?
Не приведет ли это к некоторой ошибке во время выполнения, так как this не освободит память должным образом?

(2) Переместить Назначение(станд :: Deque & & других)

Заменяет содержимое с другой использованием семантики хода (то есть данные в другом перемещаются из другога в этот контейнер). другой после этого находится в правильном, но неуказанном состоянии. Если std :: allocator_traits :: propagate_on_container_move_assignment() is 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 Jan 16

либо в виде копии или переместить задание, его поведение зависит от двух условий:
1. является распределители сравнить равны? (То есть, источник-распределитель способен уничтожать и освобождать элементы целевого контейнера?)
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; 
}