2010-01-21 9 views
7

Mam wskaźnik do struktury i muszę wdrożyć metodę, która skopiuje całą zawartość pamięci struktury. Ogólnie mówiąc, muszę wykonać głęboką kopię struktury.C++: Czy struktura będzie poprawnie skopiowana?

Oto struktura:

typedef struct { 
    Size2f spriteSize; 

    Vertex2f *vertices; 

    GLubyte *vertex_indices; 
} tSprite; 

A oto metoda I zostały wdrożone, że należy skopiować strukturę:

tSprite* copySprite(const tSprite *copyFromMe) 
{ 

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

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

    return pSpriteToReturn; 
} 

Problemem jest to, że nie jestem pewien, że tablice „wierzchołki” a "vertex_indices" zostaną poprawnie skopiowane. Co będzie kopiowane w ten sposób? Adres tablicy lub samej tablicy?

Czy należy skopiować tablice po skopiowaniu struktury? A może wystarczy skopiować strukturę?

coś takiego:

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

Z góry dziękuję.

+2

To zależy. Czy kopią powinna być kopia głęboka, z niezależnymi * wierzchołkami i * wierzchołkami_indeksów, czy też obie kopie powinny mieć jedną kopię danych? Jak napisano, twój copysprite będzie tylko płytko kopiował wskaźniki i będą one miały wspólne dane. – Joe

+3

Nie wiem, dlaczego otagowałeś to C++, gdy cały twój kod jest prosty C. –

+0

Jeśli problem dotyczy C. Wtedy to poprawnie robi płytką kopię. Jeśli problem dotyczy C++, otwieramy całą puszkę robaków, na którą nie można odpowiedzieć, ponieważ nie ma wystarczającej ilości informacji. –

Odpowiedz

8

Jako zasada, Nie wolno stosować memcpy w C++ w normalnym kodu (to siła upraw w samym kodzie niskim poziomie, na przykład w podzielników) 1). Zamiast tego utwórz odpowiedni konstruktor kopii i przeciąż go operator = (operator przypisania), aby dopasować go (i do destruktora - zasada trzech: "jeśli zastosujesz jeden z konstruktorów kopiowania, operator = i destruktor, musisz musi zaimplementować wszystkie trzy) .

Jeśli nie zaimplementujesz własnych wersji konstruktora kopiowania, operator przypisania C++ utworzy dla ciebie wersje domyślne. Wersje te zaimplementują płytką kopię (podobnie jak to, co zrobiłby plik memcpy), tj. W twoim przypadku zawartość tablicy byłaby kopiowana - nie tylko - tylko wskaźniki.


1) Nawiasem mówiąc, to samo dotyczy malloc i free. Nie używaj ich, zamiast tego użyj new/new[] i delete/delete[].

+0

Dzięki, ale co z kopiowaniem tablic w stylu c? Jak mogę je skopiować bez użycia memcpy? –

+1

użyj nowego [], aby przydzielić, std :: copy, aby skopiować, usunąć [], aby usunąć – Anycorn

+0

@Ilya: możesz użyć 'std :: copy'. Z drugiej strony, czy naprawdę musisz używać tablic w stylu C i czy "std :: vector" nie jest lepszym rozwiązaniem? –

3

Częściowo zależy to od Twoich wymagań. Jeśli nie skopiujesz tablic, obie struktury będą wskazywać na tę samą tablicę, co może, ale nie musi być problemem.

3

Twój schemat skopiuje adresy tablic. Zwrócona "kopia" tSprite będzie miała wskaźniki do tych samych danych (w pamięci), co przekazane w jednym.

Jeśli potrzebujesz prawdziwej kopii w tle, musisz ręcznie skopiować tablice (i dowolne elementy ich elementów).

2

Jeśli piszesz w C++, to pamiętaj, że C++ ma z jednego powodu new i delete. Jeśli chodzi o samo pytanie, to zależy od tego, czy chcesz skopiować wskaźniki, czy same struktury. Jeśli to drugie, musisz je także skopiować!

+0

Co skłoniłoby Cię do myślenia, że ​​autor pisze w C++? –

+0

@dash: tag C++ w pytaniu? ;> –

1

To nie jest dobry sposób na kopiowanie, nawet jeśli pracujesz w zwykłym C.

Wskazana w drugiej odpowiedzi, otrzymasz dwie (lub więcej) instancje struct wskazujące na tę samą instancję Vertext2 i GLubyte, co nie jest zalecane.

będzie to prowadzić do problemów, jak kto uwolni pamięć przeznaczyć do Vertext2GLubyte

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

Tak to jest właściwy sposób to zrobić

1

Wskaźniki sami będą skopiowane, ale że oznacza, że ​​zarówno "od", jak i "do" będą takie same w dwóch duszkach. Będziesz także potrzebował ręcznie przydzielać i kopiować rzeczy wskazywane przez wskaźniki, ale to oznacza, że ​​musisz również wiedzieć, jak duże są tablice, do których odnoszą się wskaźniki.

Zauważ, że zamiast memcpy tam, możesz również zrobić "* pSpriteToReturn = * copyFromMe;" Spowoduje to skopiowanie wszystkich członków, ale jeśli zamierzasz tworzyć nowe tablice, jedyną częścią TSprite, którą chcesz skopiować, jest rozmiar.

Inną nutą byłoby to, że jeśli twoje duszki mają zawsze ustaloną liczbę wierzchołków i indeksów wierzchołków, możesz uczynić te tablice wewnątrz sprite'a, a nie wskaźniki. Jeśli to zrobisz, zostaną one skopiowane poprawnie zarówno przy pomocy metody memcpy, jak i przydziału, o którym wspomniałem w powyższym akapicie.

1

w C++ nowe i usuń alokację na stercie.

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