Могу ли я использовать memcpy() любого типа с тривиальным деструктором?

Я понимаю, что is_pod является достаточным условием для того, чтобы тип мог быть memcpy, но достаточно ли также has_trivial_destructor для этой цели? Если нет, то почему?


person user541686    schedule 16.08.2012    source источник
comment
Я думаю, вы имеете в виду is_trivially_destructible.   -  person GManNickG    schedule 16.08.2012
comment
@GManNickG: я не слышал об этом, спасибо.   -  person user541686    schedule 16.08.2012
comment
Только когда вы отправили меня в погоню за дикими гусями по стандарту, я тоже выучил правильный термин. :)   -  person GManNickG    schedule 16.08.2012
comment
@GManNickG и Mehrdad has_trivial_destructor были в TR1 и, вероятно, в некоторых более ранних черновиках, но позже переименованы. Я думаю, что GCC 4.6 по-прежнему поставлял трейты has_blah_blah вместо версий is_blah_blah.   -  person R. Martinho Fernandes    schedule 16.08.2012
comment
@R.MartinhoFernandes: мне показалось, что это звучит знакомо, спасибо за разъяснения.   -  person GManNickG    schedule 16.08.2012


Ответы (4)


Нет. Требование состоит в том, чтобы тип был тривиально копируемым (§3.9/2), который имеет еще несколько требований, например отсутствие нетривиального конструктора копирования (§9/6).

Тривиально копируемый класс — это класс, который:

— не имеет нетривиальных конструкторов копирования (12.8),

— не имеет нетривиальных конструкторов перемещения (12.8),

— не имеет нетривиальных копирующих операторов присваивания (13.5.3, 12.8),

- не имеет нетривиальных операторов присваивания перемещения (13.5.3, 12.8) и

— имеет тривиальный деструктор (12.4).

Поэтому вместо этого вы должны использовать is_trivially_copyable.

person R. Martinho Fernandes    schedule 16.08.2012
comment
is_trivially_copyable, похоже, широко не задокументировано, у вас есть ссылка? Неважно, нашел это здесь: en.cppreference.com/ w/cpp/types/is_tribuly_copyable - person Mark Ransom; 16.08.2012
comment
@MarkRansom: таблица 49 в последнем черновике, §20.9.4.3. - person GManNickG; 16.08.2012
comment
Я предлагаю дополнительно проверить is_copy_constructible<T>, потому что это ловит удаленные конструкторы копирования. Я чувствую, что, хотя memcpy может иметь смысл подорвать частный тривиальный ctor копирования (в конце концов, это может быть автор класса, которым memcpy их), удаленный тривиальный ctor копирования не имеет смысла подрывать memcpy IMHO. Попытка memcpy их как более оптимизированную версию алгоритмов, таких как std::copy, должна потерпеть неудачу для удаленных копий IMHO. - person Johannes Schaub - litb; 19.08.2012

Недостаточно, чтобы объект имел тривиальный деструктор. Он также должен иметь тривиальные операции копирования. Например, объект может поддерживать указатели на внутренние буферы. Нет необходимости что-либо уничтожать, но при копировании потребуется настроить указатели в копируемом объекте, потому что в противном случае они указывали бы на буфер исходного объекта.

person Dietmar Kühl    schedule 16.08.2012
comment
+1 Я всегда забываю о возможности указателей на внутренние буферы. ›_‹ - person user541686; 16.08.2012

Хотя на практике это редкость, может возникнуть ситуация, когда класс имеет нетривиальный конструктор копирования вместе с тривиальным деструктором. Рассмотрим класс со статической переменной-членом, которая просто подсчитывает, сколько раз класс был скопирован. Если вы memcpy сделаете это, счетчик будет неточным.

person Charles Salvia    schedule 16.08.2012
comment
Кстати, в стандарте четко указано, что вы не должны зависеть от побочных эффектов конструкторов копирования, поскольку копии могут выполняться или исключаться в различных обстоятельствах, поэтому точность такого счетчика будет в лучшем случае ограниченной. - person David Rodríguez - dribeas; 16.08.2012
comment
@DavidRodríguez-dribeas: Копии могут быть опущены, но если они есть, их нужно полностью опустить. т.е. такой счетчик копий будет обновляться тогда и только тогда, когда копия действительно была сделана. Это, конечно, важно для таких классов, как shared_ptr<>. Компилятор может опустить копии shared_ptr, но это не приведет к утечке памяти. - person MSalters; 16.08.2012
comment
@MSalters: я не говорю, что это будет безопасно, просто такой счетчик будет неточным по определению. - person David Rodríguez - dribeas; 16.08.2012

Мне кажется, что класс с простым указателем будет квалифицироваться как has_trivial_destructor, но обычно вы хотите сделать глубокую копию, тогда как memcpy создаст поверхностную копию.

person Mark Ransom    schedule 16.08.2012
comment
Что ж, если класс тривиально разрушаем, ему нужно нарушить правило трех, чтобы иметь копирующий конструктор с глубоким копированием. :) Тем не менее, я думаю, что вопрос касается неопределенного поведения, т. Е. Если is_trivially_destructible<T>::value равно true, то memcpying a T четко определено. - person GManNickG; 16.08.2012