В C у нас есть функции memcpy
и memmove
для эффективной копирования данных. Первое дает неопределенное поведение, если область источника и получателя перекрывается, но последнее гарантировано имеет дело с тем, что «как ожидалось», предположительно, заметив направление перекрытия и (при необходимости) выбрав другой алгоритм.Копирование классов между диапазонами, которые могут перекрываться
Вышеуказанные функции доступны в C++ (как std::memcpy
и std::memmove
), конечно, но они не работают с нетривиальными class
es. Вместо этого мы получаем std::copy
и std::copy_backward
. Каждое из них работает, если диапазоны источника и назначения не перекрываются; кроме того, каждый гарантированно работает для одного «направления» перекрытия.
Что мы можем использовать, если мы хотим скопировать из одного региона в другой, и мы не знаем во время компиляции, если диапазоны могут пересекаться или в каком направлении может возникать совпадение? Кажется, у нас нет возможности. Для общего iterator
s может быть трудно определить, перекрываются ли диапазоны, поэтому я понимаю, почему в этом случае не предусмотрено решение, но о том, когда мы имеем дело с указателями? В идеале, было бы функция, как:
template<class T>
T * copy_either_direction(const T * inputBegin, const T * inputEnd, T * outputBegin) {
if ("outputBegin ∈ [inputBegin, inputEnd)") {
outputBegin += (inputEnd - inputBegin);
std::copy_backward(inputBegin, inputEnd, outputBegin);
return outputBegin;
} else {
return std::copy(inputBegin, inputEnd, outputBegin);
}
}
(Аналогичная функция T *
заменена std::vector<T>::iterator
бы неплохо еще лучше было бы, если бы это было гарантированно работать, если inputBegin == outputBegin
, но это a separate gripe of mine.).
К сожалению, я не вижу разумного способа записать условие в инструкции if
, поскольку сравнение указателей на отдельные блоки памяти часто приводит к неопределенному поведению. С другой стороны, реализация, очевидно, имеет свой собственный способ сделать это, потому что std::memmove
по своей сути требует этого. Таким образом, любая реализация может обеспечить такую функцию, тем самым заполняя потребность в том, что программист просто не может. Поскольку std::memmove
считался полезным, почему бы не copy_either_direction
? Есть ли решение, которое мне не хватает?
Поскольку классы могут содержать не-POD типов, такие как 'станд :: string' или' станд :: VECTOR' , вы рассматриваете возможность глубокого перемещения? –
Я рассматриваю возможность запуска любой функции копирования, которую использует класс. –
Можете ли вы привести пример, где регион может пересекаться? Чтобы получить перекрывающиеся области, вам нужно будет сделать некоторые небезопасные типы. «Memmove» - это функция низкого уровня, касающаяся перемещения содержимого памяти без каких-либо конструкций высокого уровня. Алгоритмы более высокого уровня 'std :: copy' вызывают конструкторы, которые улучшают безопасность, но уменьшают эффективность. –