C ++: структура будет скопирована правильно? - PullRequest
7 голосов
/ 21 января 2010

У меня есть указатель на структуру, и мне нужно реализовать метод, который будет копировать все содержимое памяти структуры. Вообще говоря, мне нужно выполнить глубокую копию структуры.

Вот структура:

typedef struct { 
    Size2f spriteSize;

    Vertex2f *vertices;

    GLubyte *vertex_indices;
} tSprite;

А вот метод, который я реализовал, который должен копировать структуру:

tSprite* copySprite(const tSprite *copyFromMe)
{

    tSprite *pSpriteToReturn = (tSprite*)malloc( sizeof(*copyFromMe) );

    memcpy(pSpriteToReturn, copyFromMe, sizeof(*copyFromMe) );

    return pSpriteToReturn;
}

Проблема в том, что я не уверен, что массивы "vertices" и "vertex_indices" будут скопированы правильно. Что будет скопировано таким образом? Адрес массива или самого массива?

Должен ли я копировать массивы после копирования структуры? Или достаточно просто скопировать структуру?

Примерно так:

...
pSpriteToReturn->vertices = (Vector2f*)malloc( sizeof(arraysize) );
memcpy(pSpriteToReturn->vertices, copyFromMe->vertices, sizeof(arraysize) );
...

Заранее спасибо.

Ответы [ 7 ]

8 голосов
/ 21 января 2010

Как правило, никогда не используйте memcpy в C ++ в обычном коде (это может появляться в коде очень низкого уровня, например, в распределителях) 1) . Вместо этого создайте подходящий конструктор копирования и перегрузите operator = (оператор присваивания) для его сопоставления ( и деструктор - правило трех: «если вы реализуете либо конструктор копирования, operator = и деструктор, вы должны реализовать все три).

Если вы не реализуете свои собственные версии конструктора копирования и оператора присваивания, C ++ создаст версии по умолчанию для вас. В этих версиях будет реализована мелкая копия (во многом аналогично тому, что сделал бы memcpy), т. Е. В вашем случае содержимое массива не будет скопировано - только указатели.


1) Кстати, то же самое относится к malloc и free. Не используйте их, вместо этого используйте new / new[] и delete / delete[].

3 голосов
/ 21 января 2010

Ваша схема будет копировать адреса массивов. Возвращенная «копия» tSprite будет иметь указатели на те же данные (в памяти), что и переданные в один.

Если вам нужна настоящая глубокая копия, вам нужно скопировать массивы (и любые элементы их элементов) вручную.

3 голосов
/ 21 января 2010

Это частично зависит от ваших требований. Если вы не копируете массивы, обе структуры будут указывать на один и тот же массив, что может быть или не быть проблемой.

2 голосов
/ 21 января 2010

Если вы пишете на C ++, помните, что C ++ имеет причины new и delete. Что касается самого вопроса, это зависит от того, хотите ли вы скопировать указатели или сами структуры. Если последнее, вам нужно скопировать их тоже!

1 голос
/ 21 января 2010

в C ++ new и delete выделяют в куче.

Sprite *ptr =...;
Sprite *s = new Stripe(*ptr); // copy constructor, shallow copy off pointers
s->member = new Member(*ptr->member); // copy construct sprite member

s->array = new int[4]; //allocate array
std::copy(ptr-> array, ptr->array + 4, s->array); //copy array
delete[] s->array; //delete array, must use delete[]
1 голос
/ 21 января 2010

Сами указатели будут скопированы, но это означает, что оба «от» и «до» будут одинаковыми в двух спрайтах. Вам также нужно будет вручную распределять и копировать объекты, на которые указывают указатели, но это также означает, что вам также необходимо знать, насколько велики массивы, на которые ссылаются указатели.

Обратите внимание, что вместо memcpy вы также можете сделать '* pSpriteToReturn = * copyFromMe;' Это скопирует всех участников, хотя если вы собираетесь создавать новые массивы, единственная часть tSprites, которую вы хотите скопировать, это размер.

Еще одно замечание: если ваши спрайты всегда имеют фиксированное количество вершин и индексов вершин, вы можете создавать эти массивы внутри спрайта, а не указателей. Если вы это сделаете, они будут правильно скопированы как с помощью метода memcpy, так и с заданием, которое я упомянул в предыдущем абзаце.

1 голос
/ 21 января 2010

Это неправильный способ копирования, даже если вы работаете на обычном C.

Как указано в другом ответе, вы получите два (или более) экземпляра структуры, указывающих на один и тот же экземпляр Vertext2 и GLubyte, что не рекомендуется.

Это может привести к проблемам, например, кто освободит память, выделенную для Vertext2 GLubyte

Should I copy the arrays after copying the structure? Or is it enough just to copy the structure?

Да, это правильный способ сделать это

...