2016-01-21 1 views
1

Итак, у меня есть следующий код, упрощенная версия того, что я хочу сделать. У меня есть класс с переменной-членом, который я хочу установить для потенциально различных типов данных, в зависимости от ситуации (я просто сделал случайную структуру для этого теста). Тем не менее, я все-таки получаю seg-ошибки в функции memcpy, и я понятия не имею, почему.Почему эта memcpy не работает?

#include <cstdlib> 
#include <iostream> 
#include <assert.h> 
#include <string> 
#include <string.h> 
#include <stdio.h> 
using namespace std; 

struct product 
{ 
     int price; 
     string name; 
}; 


class object 
{ 
public: 
     void setData(void *ptr); 
     void* data; 
}; 


void object::setData(void *ptr) 
{ 
     assert(ptr); 
     memcpy(data, ptr, sizeof(ptr)); 
} 


int main() 
{ 
     product* bag; 
     product ba; 
     bag = &ba; 
     bag->price = 5; 
     bag->name = "bag"; 

     object test; 
     test.setData(bag); 

     cout<<test.data->name<<endl; 

     return 0; 
} 
+4

'sizeof (ptr)' ???? Что вы ожидаете от этого? –

+1

Кроме того, вы не можете просто «memcpy» создать строковый объект. –

+1

И даже если вы правильно задали 'sizeof', вы не можете использовать' memcpy' для не-POD-типов, например, ваш класс 'product'. – PaulMcKenzie

ответ

5

Ваш код имеет несколько проблем, но непосредственная причина SIGSEGV является следующей строкой: memcpy(data, ptr, sizeof(ptr));, который пытается скопировать несколько байт в нераспределенном указатель data.

На стороне примечания, похоже, вы пытаетесь добиться полиморфизма в C++, используя полностью inapproriate методы.

0

Кроме того, я предполагаю, что это может быть проблема здесь

cout<<test.data->name<<endl; 

случае данные недействителен указатель так что вам нужно бросить здесь

cout<<static_cast<product *>(test.data)->name<<endl; 
2

Другие упоминали, что memcpy не является правильной в связи с использованием sizeof(void*), как количество байтов для копирования. Но изменение sizeof на соответствующее значение просто приведет вас к следующему камню преткновения с использованием memcpy. Вы, вероятно, столкнуться с ним, как только вы выполните эту строку:

cout<<test.data->name<<endl 

Причина заключается в том, что data->name больше, чем, вероятно, испорчен, недействительно, если вы на самом деле видите название печатается строка находится в нестабильном состоянии ,

В принципе, использование memcpy для установки структуры на определенное значение не будет работать, если структура не является POD.

What is a POD type?

POD updates for C++ 11

Ваш product класс имеет элемент, который не является POD типа, а именно std::string. Вы не можете просто наложить объект std::string с байтами данных из другого объекта std::string (это то, что будет делать memcpy).

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

В отличие от типов POD, простое копирование таких байтов испортит целевой объект. Если этот объект содержит, скажем, v-таблицу, то вы действительно будете копировать объект назначения в клочки.

Для типов, отличных от POD, используйте соответствующие методы C++, которые включают использование присвоения (data = ptr).

+0

Как ни странно, 'std :: string' ** почти ** POD.Единственное, что мешает ему быть POD, - это различный контроль доступа, но вряд ли это вызовет проблемы с memcpy. – SergeyA

+0

Извините, мне пришлось использовать downvote для обозначения устаревшего определения POD. – SergeyA

+0

Наличие нетривиального деструктора также предотвращает «std :: string» от «почти POD». – PaulMcKenzie