Как копирование данных из одной структуры данных в другую работает в C ++? - PullRequest
1 голос
/ 19 августа 2011

У меня есть класс, который выглядит так:

class A
{
  public:
       A();
       void MethodThatWillNotBeInOtherStructure();

       inline int getData() { return data; }
       inline void setData(int data_) { data = data_; }

  private:
       int data;
}

и структура типа:

struct B
{
  public:         
       inline int getData() { return data; }
       inline void setData(int data_) { data = data_; }

  private:
       int data;
}

Как я могу скопировать экземпляр A в B без индивидуальной настройки полей? Я знаю, что могу, так как видел код, который мог бы взять пустое * слово A и передать его функции, ожидающей B, и это сработает. Мой большой вопрос также, как это работает? Я предполагаю, что это как-то связано с memcpy, но я не знаю, как будет выглядеть структура памяти для структуры и класса. Например, как функции, находящиеся в одной, но не в другой, не мешают работе memcpy? Может ли кто-нибудь объяснить это мне?

Обновление

Хорошо, позвольте мне объяснить. Я не говорю, что когда-нибудь сделаю это в коде многократного использования или что я буду когда-либо использовать его. Я все еще хочу знать, как это работает. У класса есть разная структура памяти, чем у структуры? Как хранятся методы? Где хранятся данные?

Спасибо!

Ответы [ 4 ]

2 голосов
/ 19 августа 2011

Знание структуры памяти очень важно, когда вы используете небезопасные механизмы, такие как memcpy, для копирования структуры.Как только это будет изменено позже, вся ваша логика может испортиться.

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

Я бы предложил вам определить operator =, конструкторы для соответствующего приведения одного объекта к другому..

Дополнительным недостатком memcpy является то, что объект может содержать виртуальный указатель, если у класса есть виртуальные функции.Дополнительные данные указателя также могут быть скопированы в целевую память;что не очень хорошо!

2 голосов
/ 19 августа 2011

Копирование двух несвязанных структур друг с другом через void * будет работать правильно, только если две структуры имеют одинаковую структуру памяти. В противном случае копирование не удастся.

Обратите внимание, что объекты структуры A и B в приведенном выше коде будут иметь одинаковую структуру памяти, поскольку переменные-члены идентичны.

Копирование через void * работает, потому что вы просто копируете фактическую память, занятую одним структурным объектом, в память, занятую другим структурным объектом.

По сути, плохая идея копировать две несвязанные структуры таким образом.

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

Как хранятся методы? Где хранятся данные?
Нормальная функция (не виртуальная) будет храниться где-то в разделе кода программы. Это расположение одинаково для всех экземпляров класса / структуры и, следовательно, оно не является частью распределения памяти каждого объекта класса / структуры.

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

1 голос
/ 19 августа 2011

Вы можете скопировать A в B, используя memcpy, так как они имеют одинаковые переменные-члены.Функции не являются частью экземпляров, поэтому они не имеют значения.

Я бы рекомендовал против такого подхода.Если изменится либо A, либо B, ваша копия потерпит неудачу во время выполнения.Вы можете создать конструктор из B, который принимает A, функцию преобразования или что-то еще.Хотя для этого потребуется немного больше кода, он позволит вносить изменения в структуры.

0 голосов
/ 19 августа 2011

Лучше всего, вероятно, реализовать конструктор структуры B, который принимает константную ссылку на структуру A. Используйте это напрямую или используйте оператор присваивания (который вам, вероятно, понадобится реализовать для нетривиальных случаев).

A a;
... (populate a)

B b(a); //If you want to set b to a at instantiation.

b = B(a); //If you want to overwrite an existing instance of struct B with a.

РЕДАКТИРОВАТЬ: Чтобы ответить на ваши изменения, это полностью зависит от компилятора.Тот факт, что он работает для класса, зависит от деталей компилятора, поскольку AFAIK не поддерживается стандартом.Разработчики компилятора могут решить связываться с людьми, заставляя его работать на CLASS, но не на STRUCT (или наоборот).

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

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