C ++ гарантия и имя для POD-подобных данных, с поддержкой memcpy - PullRequest
17 голосов
/ 25 марта 2011

В другом вопросе я неправильно использовал термин POD для обозначения типов данных, которые на самом деле не являются типами POD (из-за наличия конструктора). Теперь я просмотрел стандарт и не смог найти подходящего названия для того, что я хочу. Также я не могу найти гарантию того, что копирование действительно разрешено.

Тип данных, который я имею в виду, является POD, но может содержать функции, включая конструкторы, но ничего, что не должно изменять его характеристики выравнивания или размера по сравнению с эквивалентным типом POD.

В разделе 3.9 стандарта говорится, что данные POD могут быть скопированы с помощью memcpy либо в другой объект, либо в символьные данные и обратно. На данные, не относящиеся к POD, такая гарантия не предоставляется.

Однако, представление объекта объекта определено в том же разделе. Он определен так, что можно полагать, что любые два объекта одного типа могут быть безопасно скопированы через memcpy.

Итак, мои вопросы:

  1. Действительно ли копия с memcpy безопасна для таких объектов?
  2. Если да, то почему есть специальное примечание о memcpy и POD?
  3. Существует ли название для этого типа данных, которое безопасно для memcpy?

Простой пример типа объекта, который я имею в виду:

struct ex_struct
{
  int a,b,c,d;
  ex_struct() : a(123) { }
}

При чтении черновика C ++ 0x моя структура выглядит как тривиально копируемый класс (9.1). Я полагаю, это подразумевает, что memcpy будет безопасным.

Ответы [ 4 ]

7 голосов
/ 28 марта 2011

В C ++ 0x концепция PODness разбита на несколько индивидуально полезных категорий:

A тривиально копируемый класс - это класс, который (черновик 3242, раздел[class]):

  • не имеет нетривиальных конструкторов копирования (12.8),
  • не имеет нетривиальных конструкторов перемещения (12.8),
  • не имеетнетривиальные операторы назначения копирования (13.5.3, 12.8),
  • не имеет нетривиальных операторов назначения перемещения (13.5.3, 12.8), а
  • имеет тривиальный деструктор (12.4).

A тривиальный класс - это класс, имеющий тривиальный конструктор по умолчанию (12.1) и тривиально копируемый.

[ Примечание: В частности, тривиально копируемый или тривиальный класс не имеет виртуальных функций или виртуальных базовых классов.- примечание конца ]

A класс стандартной компоновки - это класс, который:

  • не имеет нестатических элементов данных типакласс нестандартной компоновки (или массив таких типов) или ссылка,
  • не имеет виртуальных функций (10.3) и виртуальных базовых классов (10.1),
  • имеет одинаковое управление доступом (Пункт 11) для всех нестатических элементов данных
  • не имеет базовых классов нестандартной компоновки,
  • либо не имеет нестатических элементов данных в наиболее производном классе и не более одногобазовый класс с нестатическими элементами данных или не имеет базовых классов с нестатическими элементами данных, а
  • не имеет базовых классов того же типа, что и первый нестатический элемент данных.

Требования к тривиальным конструкторам, операторам присваивания и деструктору разбросаны по всему разделу 12 «Специальные функции-члены» [special].

4 голосов
/ 25 марта 2011

Понятие POD в C ++ 03 действительно слишком строго. В C ++ 0x POD обобщён и включает объекты, которые вы описали. Так что не волнуйтесь, вы можете назвать это POD. Смотрите хорошее лето в Википедии .

1 голос
/ 25 марта 2011

Одна из проблем вашего примера в том, что он имеет неявно объявленный, тривиальный деструктор.Несмотря на название, реализация не запрещает AFAIK делать что-то в тривиальном деструкторе класса, не являющегося POD.

Так что с юридической точки зрения в какой-то странной реализации ваш класс ex_struct может демонстрировать поведение во время выполнения, эквивалентное следующему:

struct weird_ex_struct
{
  int a,b,c,d;
  weird_ex_struct() : a(123), aptr(&a) { }
  weird_ex_struct(const weird_ex_struct &o) : 
    a(o.a), b(o.b), c(o.c), d(o.d), aptr(&a) {}
  weird_ex_struct &operator=(const weird_ex_struct &o) {
    a = o.a; //etc
    aptr = &a;
    return *this;
  }
  ~weird_ex_struct() {
    if (aptr != &a) std::terminate();
  }
private:
  int *aptr;
}

Я говорю поведение во время выполнения, потому что weird_ex_struct имеет нетривиальный деструктор, и это влияет на то, как его можно использовать на законных основаниях (с одной стороны, не в профсоюзах).Кроме того, я думаю, что есть стандартные способы обнаружения существования закрытых элементов данных во время компиляции.Но до тех пор, пока реализация может хранить эту информацию в секрете, если вы не сделаете что-то неопределенное (memcpy объект, не являющийся POD), тогда можно будет преподнести сюрприз вам позже.

Ясно, если weird_ex_structскопированный с memcpy, тогда, когда он будет уничтожен, произойдет что-то странное.

Нет очевидной причины для реализации, чтобы сделать это, но стандартные левые не-POD классы широко открыты для реализаций, чтобы делать странные вещи.Не уверен, что это потому, что они думали, что кто-то подумает о какой-то полезной странности, или просто потому, что не удосужились определить стандартную компоновку , как это делает C ++ 0x.

[Редактировать: Йоханнес указал, что я ошибаюсь в отношении тривиальных деструкторов - по причинам, изложенным в части стандарта, касающейся времени жизни объекта, реализация не может делать вещи в тривиальных деструкторах, которые полагаются на содержимое памяти объекта,Возможно, они могут, если деструктор вызывается явно, я не уверен.

Тем не менее, факт остается фактом: стандарт позволяет реализациям делать довольно много сумасшедших вещей с объектами, отличными от POD, и как тольковы пишете конструктор, вы открываете эту дверь.]

0 голосов
/ 25 марта 2011

Да, безопасно копировать с помощью memcpy, потому что вы конструктор только инициализируете значения.

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