Ограничения std :: copy более мягкие, чем std :: memcopy?

С учетом на проблемы copy vs. memcpy vs memmove (отличная информация здесь, кстати.), я читал, и мне показалось, что в отличие от того, что в разговорной речи говорится, например, на cppreference Примечание. После взятия этой цитаты memcpy был изменен на memmove. -

Примечания

На практике реализации std::copy избегают множественных назначений и используют функции массового копирования, такие как std::memcpy, если тип значения TriviallyCopyable

- std::copy (или std::copy_backward) нельзя реализовать в терминах memcopy, потому что для std::copy только начало целевого диапазона не должно попадать в исходный диапазон, а для memcpy все диапазоны не должны перекрываться.

Глядя на реализацию Visual-C ++ (см. Заголовок xutility), мы также можем заметить, что VC ++ использует memmove, но этот теперь имеет более мягкие требования, чем std::copy:

... Объекты могут перекрываться: копирование происходит так, как если бы символы были скопированы во временный массив символов, а затем символы были скопированы из массива ...

Таким образом, может показаться, что реализация std::copy с точки зрения memcpy невозможна, но использование memmove на самом деле является пессимизацией. (крохотная пессимизация, возможно, неизмеримая, но все же)

Возвращаясь к вопросу (ам): Верно ли мое резюме? Это где-нибудь проблема? Независимо от того, что указано, существует ли вообще возможная практическая реализация memcpy, которая также не соответствовала бы требованиям std::copy, т.е. существуют ли memcpy реализации, которые нарушаются при частичном перекрытии диапазонов как разрешено std::copy?


person Martin Ba    schedule 25.10.2013    source источник
comment
Во-первых, реализация std::copy не обязательно должна быть строго переносимой и может использовать сведения о деталях реализации memcpy (например, что на самом деле нормально копировать между перекрывающимися областями, если они перекрываются правильно). Во-вторых, даже если он решит не делать этого, он все равно может проверять диапазоны и откладывать memcpy, когда они не перекрываются (то есть большую часть времени).   -  person Igor Tandetnik    schedule 26.10.2013
comment
libc ++ и stdlibc ++ также вызывают memmove, я изменил это примечание о cppreference, чтобы сказать memmove.   -  person Cubbi    schedule 29.10.2013
comment
stackoverflow.com/q/19585930/321013   -  person Martin Ba    schedule 29.10.2013
comment
vgable.com/blog/2008/05 / 24 /   -  person Martin Ba    schedule 29.10.2013


Ответы (1)


Если вопрос в том, можно ли встретить эффективную реализацию memcpy с достаточно неопределенным поведением, чтобы не доверять ей в перекрывающихся диапазонах, то ответ - да. :-)

Рассмотрим одну возможную реализацию memcpy в архитектуре Power (ПК): инструкция lmw будет загружать несколько последовательных слов из памяти в последовательные регистры (которые можно указать как аргумент диапазона, определяемый пользователем). stmw затем сохранит предоставленный диапазон регистров обратно в память. Таким образом, мы говорим о ~ 100/200 байт (32b / 64b CPU), буферизованных CPU во время одной итерации memcpy - много данных, чтобы испортить целевой диапазон, если он перекрывается с исходным, особенно учитывая, что CPU не дает никаких обещаний об относительном порядке индивидуальной загрузки и запасов.

person oakad    schedule 29.10.2013
comment
Как насчет компилятора, который, учитывая void f(char *p,char*q) { if (p!=q) doSomething();} void g(char *p,char *q) { f(p,q); memcpy(p,q,sizeof *p); }, сделает вывод, что Стандарт не налагает никаких требований на поведение g, когда p == q, таким образом разрешая вызов doSomething (); быть безусловным? - person supercat; 31.10.2015