Почему SGI STL не использует идиому копирования и обмена?

Я недавно прочитал ответ на 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;
}

6

Решение

Код, который вы показываете, не перераспределяет память, если контейнер не должен расти, что может значительно сэкономить. Копирование и замена всегда выделяет память для выполнения копирования, а затем освобождает память для существующих элементов.

Рассмотрим deque<vector<int>> где существующие векторные члены deque имеют большие возможности.

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 ++, вы не хотите жертвовать эффективностью ради немного более простой реализации, и такой код обычно должен быть написан экспертами, которые способны получить право на исключительную безопасность, выполняя это «трудным путем». «Не просто самый удобный способ.

8

Другие решения

Идиома — это простой способ обеспечить надежную гарантию исключения, и поэтому это «лучшая практика» в смысле хорошей вещи, если у вас нет веской причины не делать этого.

Однако это имеет свою цену: второй объект должен быть создан и уничтожен. Это может быть дорого и, если это связано с большим выделением памяти, может увеличить пиковое использование памяти намного больше, чем необходимо. Если это вызывает озабоченность, или если вы пишете универсальную библиотеку, подобную этой, вы должны найти другие способы скопировать объект, не создавая временный объект. Безопасность исключений потребует большего внимания, чем при использовании простой идиомы.

4

Хотя копирование и замена — это лучшая практика, в некоторых случаях это может привести к снижению эффективности. В этом конкретном случае код использует тот факт, что, если назначаемому вектору уже имеется достаточно доступной памяти, значения можно просто скопировать без дополнительного выделения памяти.

3

Я предполагаю, что в этом случае это делается для того, чтобы избежать лишних перераспределений: для копирования и замены потребуется выделение копии (таким образом, занимая двойное хранилище в данный момент), а затем освобождается вся память deque. Этот код будет выделяться только в том случае, если копирование больше и требуется только разница.

Это на самом деле относится к deque, а не к vector — как там реализован vector :: operator =?

Более того, это, возможно, было написано до того, как идиома стала популярной. И даже сейчас это не принято.

2

Стандартные мандаты, которые std::deque<T>::operator=(const std::deque<T>&) должен предоставить основной гарантия исключения — то есть, что контейнер остается в действительном состоянии в случае исключения, а не сильный гарантия — что бы поспорить за использование копирования / обмена.

1
По вопросам рекламы [email protected]