Является ли это сериализацией представлений объектов с помощью memcpy без создания безопасных объектов, если у вас нет прямого доступа к содержащимся в нем значениям? - PullRequest
1 голос
/ 14 марта 2020
#include <cstdlib>
#include <cstring>
#include <iostream>

// C++03 only.
int main()
{
    std::allocator<unsigned char> alloc;

    double d = 8;
    unsigned char* buf = alloc.allocate(sizeof(double));
    std::memcpy(buf, &d, sizeof(double));

    double extract;
    std::memcpy(&extract, buf, sizeof(double));

    std::cout << extract << '\n';

    alloc.deallocate(buf, sizeof(double));
}

Я создал хранилище для массива байтов, которое я никогда не приводил в действие, инициализируя его, поэтому его время жизни никогда не начиналось (а в C ++ 03 это в принципе невозможно сделать, так как правильный путь сделать это путем размещения нового, но для массивов это добавляет смещение памяти, что вы не знаете, что это такое)

Но мне на самом деле не нужно «непосредственно читать» данные, которые в этом память, я делаю всю эту копию-вставку объектов с помощью std::memcpy вызовов.

Я сомневаюсь со вторым вызовом std::memcpy. С точки зрения доступа к значениям считается ли, что std::memcpy читает значение каждого элемента массива buf, поэтому этот массив должен быть жив?

ПРИМЕЧАНИЕ: Было предложено что этот вопрос является возможным клоном Можно ли использовать memcpy для типа punning? . Этот другой вопрос касается C, и этот вопрос также не относится к наказанию типов, хотя он связан (изначально я написал неправильное название вопроса, потому что я неправильно понял, что на самом деле означает наказание типов). Я спрашиваю здесь о точной семантике объекта чтения из, который передается в memcpy, должен ли этот объект быть живым или на самом деле не требуется.

1 Ответ

2 голосов
/ 15 марта 2020

std::allocator<unsigned char>::allocate определяется как вызывающий ::operator new (C ++ 03 lib.allocator.members / 3). Таким образом, этот вопрос в значительной степени похож на «конструирование» тривиально копируемого объекта с помощью memcpy , хотя без попытки затем псевдонима ввести значение.

Если мы заменили вызов на memcpy на присваивание символа l oop: unsigned char *p = (unsigned char *)&d; for (int i = 0; i < sizeof d; ++i) buf[i] = p[i];, тогда это определенно неопределенное поведение, поскольку оператор присваивания имеет определенное поведение, только когда левая часть ссылается на существующий объект. См. Этот ответ для получения более подробной информации. .

Однако для версии memcpy возникает вопрос: является ли memcpy таким же, как это присвоение символа l oop, или что-то еще?

Стандарт C ++ 03 определяет memcpy только путем отсрочки до ISO C90, которая гласит:

Функция memcpy копирует n символов из объекта, на который указывает s2, в объект, на который указывает s1.

Но неясно, как это интерпретировать, поскольку C имеет объектную модель, отличную от C ++. В C «объект» означает хранилище, тогда как в C ++ «объект» и «хранилище» означают разные вещи, и в коде в этом вопросе есть хранилище без объектов.

Ответ Shafik Yaghmour поэтому описывает ситуацию как «неопределенную», хотя я думаю, что «не указано» или «неясно» было бы более подходящим описанием, поскольку термин «неопределенный» имеет значение c, означающее в C ++.

Сноска: Ничего существенного не изменилось в этой топике c по состоянию на C ++ 17. Но в C ++ 20 это будет четко определено, подробности принятого предложения .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...