shanjib_
shanjib_

Reputation: 65

Why doesn't this memcpy work?

So I have the following code, a simplified version of what I want to do. I have a class with a member variable that I want to set to potentially a variety of different data types, depending on the situation (i just made a random struct for this test). I keep getting seg faults on the memcpy function though, and I have no idea why.

 #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;
}

Upvotes: 1

Views: 2756

Answers (4)

user3586901
user3586901

Reputation: 14

I know this is an old post, but I don't like any of the answers, so for future readers.

When you cast an object to a void*, you loss the type information associated with it. That is why you can't use sizeof with a void* ptr. (This is probably also why memcpy doesn't do it this way). I think what you need here is to write a Template class. Then the code will know the type and the code should work.

template<class T>
class object
{
public:
        void setData(T *ptr);
        T* data;
};


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

Upvotes: 0

PaulMcKenzie
PaulMcKenzie

Reputation: 35440

Others have mentioned that the memcpy is not correct due to using sizeof(void*) as the number of bytes to copy. But changing the sizeof to an appropriate value will just have you hit the next stumbling block with using memcpy. You would probably encounter it as soon as you execute this line:

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

The reason is that data->name is more than likely corrupted, invalid, or if you did actually see a name printed, the string is in an unstable state.

Basically, using memcpy to set a struct to a certain value isn't going to work if the struct is not a POD type.

What is a POD type?

POD updates for C++ 11

Your product class has a member that is a non-POD type, namely std::string. You cannot simply overlay a std::string object with bytes of data from another std::string object (which is what that memcpy will be doing).

The same thing can be said for functions such as memset or any C oriented function that sets the bytes of what is pointed to with values. They cannot be used on non-POD types.

Unlike POD types, just doing a copy of bytes like that will corrupt the destination object. If that object contained, say a v-table, then you really would be ripping the destination object to shreds.

For non-POD types, use the proper C++ techniques, which include using assignment (data = ptr).

Upvotes: 2

segevara
segevara

Reputation: 630

Also I suppose it could be problem here

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

case data is void pointer so you need cast here

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

Upvotes: 0

SergeyA
SergeyA

Reputation: 62553

Your code has multiple issues, but a direct cause of SIGSEGV is following line: memcpy(data, ptr, sizeof(ptr)); which tries to copy a number of bytes into unallocated pointer data.

On a side note, it looks like you are trying to achieve polymorphism in C++ using completely inapproriate methods.

Upvotes: 5

Related Questions