C++: структура будет скопирована правильно?

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

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

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 ответов

Решение

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

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


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

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

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

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

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

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

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

Это может привести к проблемам, например, кто освободит память для Vertext2GLubyte

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

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

В С ++ новые и удаляй, размещай на куче.

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[]

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

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

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

Другие вопросы по тегам