Отказ от ответственности:. Это пытается развернуть более серьезную проблему, поэтому, пожалуйста, не зацикливайтесь на том, действительно ли этот пример имеет смысл на практике.
И да, если вы хотите копировать объекты, используйте/предоставьте конструктор-копию. (Но обратите внимание, что даже пример не копирует целый объект, он пытается разбить некоторую память на несколько соседних (Q.2) целых чисел.)
Учитывая С++ Стандартная компоновка struct
, могу ли я использовать memcpy
для записи сразу нескольким (смежным) под-объектам
Полный пример: (https://ideone.com/1lP2Gd https://ideone.com/YXspBk)
#include <vector>
#include <iostream>
#include <assert.h>
#include <inttypes.h>
#include <stddef.h>
#include <memory.h>
struct MyStandardLayout {
char mem_a;
int16_t num_1;
int32_t num_2;
int64_t num_3;
char mem_z;
MyStandardLayout()
: mem_a('a')
, num_1(1 + (1 << 14))
, num_2(1 + (1 << 30))
, num_3(1LL + (1LL << 62))
, mem_z('z')
{ }
void print() const {
std::cout <<
"MySL Obj: " <<
mem_a << " / " <<
num_1 << " / " <<
num_2 << " / " <<
num_3 << " / " <<
mem_z << "\n";
}
};
void ZeroInts(MyStandardLayout* pObj) {
const size_t first = offsetof(MyStandardLayout, num_1);
const size_t third = offsetof(MyStandardLayout, num_3);
std::cout << "ofs(1st) = " << first << "\n";
std::cout << "ofs(3rd) = " << third << "\n";
assert(third > first);
const size_t delta = third - first;
std::cout << "delta = " << delta << "\n";
const size_t sizeAll = delta + sizeof(MyStandardLayout::num_3);
std::cout << "sizeAll = " << sizeAll << "\n";
std::vector<char> buf( sizeAll, 0 );
memcpy(&pObj->num_1, &buf[0], sizeAll);
}
int main()
{
MyStandardLayout obj;
obj.print();
ZeroInts(&obj);
obj.print();
return 0;
}
Учитывая формулировку в С++ Standard:
9.2 Члены класса
...
13 Нестационарные члены данных (неединичного) класса с одним и тем же контролем доступа (раздел 11) распределяются так, что последующие члены более высокие адреса внутри объекта класса. (...) Требования к выравниванию реализации могут приводить к двум смежные члены не должны быть распределены сразу друг за другом; (...)
Я бы сделал вывод, что гарантировано, что num_1
to num_3
имеют увеличивающиеся адреса и являются смежными по модулю дополнением.
Чтобы приведенный выше пример был полностью определен, я вижу эти требования, о которых я не уверен, что они держат:
-
memcpy
должно быть разрешено записывать сразу несколько "объектов памяти" таким образом, то есть- Вызов
memcpy
с целевым адресомnum_1
и размером, превышающим размер объектаnum_1
, является законным. (Учитывая, чтоnum_1
не является частью массива.) (Является memcpy (& a + 1, & b + 1, 0), определенным в C11? кажется хорошим связанным вопросом, но не совсем подходит.) - С++ (14) Стандарт, AFAICT, ссылается на описание
memcpy
на C99 Standard, и в этом говорится:
7.21.2.1 Функция memcpy
2 Функция memcpy копирует n символов из объекта, на который указывает s2 в объект, на который указывает s1.
Итак, для меня вопрос здесь по. это то, является ли целевой диапазон, который мы здесь здесь, можно рассматривать как "объект" в соответствии со стандартом C или С++. Примечание. Массив символов (часть), объявленный и определенный как таковой, можно считать считанным "объектом" для целей
memcpy
, потому что я уверен, что мне разрешено копировать с одного часть массива char в другую часть (другого) массива char.Итак, тогда вопрос был бы, если бы было законно переинтерпретировать диапазон памяти трех членов как "концептуальный" (?) char массив.
- Вызов
-
Вычисление
sizeAll
является законным, то есть использованиеoffsetof
является законным, как показано. -
Запись в дополнение между членами является законной.
Сохраняются ли эти свойства? Я пропустил что-нибудь еще?