Когда тип С++ 11 разрешен для memcpyed?
Мой вопрос следующий:
Если я хочу скопировать тип класса, memcpy может сделать это очень быстро. Это разрешено в некоторых ситуациях.
У нас есть некоторые черты типа:
- is_standard_layout.
- is_trivially_copyable.
То, что я хотел бы знать, - это точные требования, когда тип будет "побитовым".
Мое заключение состоит в том, что тип побитовоспособен, если оба свойства is_trivally_copyable
и is_standard_layout
верны:
- Это именно то, что мне нужно побитовое копирование?
- Является ли это чрезмерным?
- Недостаточно ли это?
P.S.: Конечно, результат memcpy должен быть правильным. Я знаю, что я мог бы memcpy в любой ситуации, но неправильно.
Ответы
Ответ 1
Вы можете скопировать объект типа T, используя memcpy, когда is_trivally_copyable<T>::value
- true. Нет особой необходимости в том, чтобы тип был стандартным типом макета. Определение "тривиально скопируемое" по существу состоит в том, что это безопасно для этого.
Пример класса, который можно скопировать с помощью memcpy, но который не является стандартным расположением:
struct T {
int i;
private:
int j;
};
Поскольку этот класс использует различный контроль доступа для разных нестатических элементов данных, он не является стандартным макетом, но он все еще можно копировать тривиально.
Ответ 2
Из http://en.cppreference.com/w/cpp/types/is_trivially_copyable:
Объекты тривиально-скопируемых типов являются единственными объектами С++, которые можно безопасно скопировать с помощью std::memcpy
или сериализовать в/из двоичных файлов с помощью std::ofstream::write()/std::ifstream::read()
. В общем случае тривиально-копируемый тип - это любой тип, для которого базовые байты могут быть скопированы в массив из char или unsigned char и в новый объект того же типа, и полученный объект будет иметь то же значение, что и оригинал.
Ответ 3
Если is_trivally_copyable<T>::value
(или в С++ 14 is_trivially_copyable<T>()
) не равно нулю, тип можно копировать с помощью memcpy
.
В стандарте С++ тип, который тривиально копируется, означает:
базовые байты, составляющие объект, могут быть скопированы в массив из char или без знака char. Если содержимое массива char или unsigned char копируется обратно в объект, объект должен сохранить первоначальное значение.
Однако важно понимать, что указатели также являются тривиально копируемыми типами. Всякий раз, когда в структурах данных есть указатель, вы будете копировать, вы должны быть уверены, что их копирование будет правильным.
Примеры, где опасность может быть вызвана только тем, что объект может быть тривиально скопирован:
- Реализация дерева, где ваши данные помещаются в смежный регион памяти, но с узлами, хранящими абсолютные адреса для дочерних узлов.
- Создание нескольких экземпляров некоторых данных для повышения производительности многопоточности (для уменьшения сбоев кэша), с указателями владения внутри, указав где-нибудь
- У вас есть плоский объект без указателей, но со встроенной сторонней структурой внутри. Третья структура в какой-то момент в будущем включает указатель, который не должен существовать два или более.
Поэтому всякий раз, когда вы делаете memcopying, имейте в виду, можно ли скопировать указатели в этом конкретном случае, и если все будет в порядке.
Поймите, что is_trivially_copyable
- это только сильная проверка синтаксиса ", а не " семантический тест, на языке компилятора.
Ответ 4
Объекты с тривиальными конструкторами копирования , тривиальными операциями присваивания копий и
тривиальные деструкторы могут быть скопированы с помощью memcpy
или memmove
требования для специальной функции-члена класса T
тривиальны:
Копировать конструкторы (cc) и операторы присваивания копий (ca)
- Не предоставляется пользователем (это означает, что он неявно определен или дефолт), а если он по умолчанию, его подпись такая же, как неявно определенная
-
T
имеет никаких виртуальных функций-членов
-
T
имеет виртуальных базовых классов
- Cc/ca, выбранный для каждой прямой базы
T
, тривиальный
- Выбор cc/ca для каждого типа нестатического типа (или массива типа класса) из
T
тривиальный
-
T
не имеет нестатических членов данных типа volatile-qualified (поскольку С++ 14)
деструкторы
- Не предоставляется пользователем (это означает, что он неявно определен или дефолт)
- Не является виртуальным (т.е. деструктор базового класса не является виртуальным)
- Все прямые базовые классы имеют тривиальные деструкторы
- Все нестатические члены данных типа класса (или массива типа класса) имеют тривиальные деструкторы
Просто объявление функции как = default
не делает ее тривиальной (она будет тривиальной, если
класс также поддерживает все остальные критерии для того, чтобы соответствующая функция была тривиальной)
но явно записывает функцию в код пользователя, не позволяет ей быть тривиальным. Кроме того, все типы данных, совместимые с языком C (типы POD), можно копировать тривиально.
Источник: С++ Concurrency в действии и cppreference.com
Ответ 5
То, что я понял,
- Объект должен иметь конструктор/деструктор по умолчанию.
- Операции копирования по умолчанию и перемещения.
- Нет статических и виртуальных функций с несколькими
- Спецификаторы доступа для нестатических элементов данных предотвращают важные
- Оптимизация макета имеет нестатический элемент или базу, которая не является
стандартная компоновка.
вы можете проверить, если заданный тип - это pod (Обычные старые данные), используя стандартную функцию is_pod:: значение
Ссылка: язык программирования С++ 4-е издание