Tablicowy konstruktor kopiujący

0

Mam szablon klasy

template <class T, int size>
class Klasa { public: T* Obiekty; }

W niej tablice obiektów klasy T;
W pewnej funkcji chce wykonać kopie tablicy Obiekty tak, aby każdy obiekt w nowej tablicy był utworzony za pomocą konstruktora kopiującego klasy T.

Obiekty = new T[size]; //tak alokuje Obiekty.

T* Kopia;

Kopia = new T[size](Obiekty); //tak nie działa, błąd: "Array allocated using 'new' may not have an initializer"

Kopia = calloc(size, sizeof(T));
for(int i = 0; i < size; i++)
   Kopia[i].T(Obiekty[i]); //żałosna próba wywołania konstruktora kopiującego, oczywiście zakończona błedem kompilatora "structure required on left side of ." 

Wpadłem na jeszcze jeden pomysł

Kopia = calloc(size, sizeof(T));
T* pt;
for(int i = 0; i < size; i++)
{
   pt = new T(Obiekty[i]);
   memcpy(Kopia + i, Obiekty + i, sizeof(T));
   free(pt);
}

Jednak to stwarza pewne niebespieczeństwo. Załóżmy że konstrukor klasy T gdzieś tam zapisuje wskaźnik this. Po operacji memcpy wskaźnik ten sie zmieni i zapis będzie błędny.

A więc czy da sie wywołać konstruktor kopiujący na już przydzielonym obszarze pamięci ?

0

Chyba czegoś takiego nie da się zrobić. Dana klasa musi mieć konstruktor domyślny, albo musisz znać liczbę elementów przed kompilacją, np.: Tab t[] = {Tab(1), Tab(2)};

0
adf88 napisał(a)

Załóżmy że konstrukor klasy T gdzieś tam zapisuje wskaźnik this. Po operacji memcpy wskaźnik ten sie zmieni i zapis będzie błędny.

this nigdzie nie jest zapisywany - to operator "dla programisty" ;) A nie prościej zaalokować tablicę obiektów, a potem w pętli użyć operatora '=' ???

0

this nigdzie nie jest zapisywany
e tam nigdzie, a jeśli klasa T tworzy jakieś pomocnicze klasy R i w nich zapisuje wskaźnik do siebie, wskaźnik do rodzica :)

0
adf88 napisał(a)

this nigdzie nie jest zapisywany
e tam nigdzie, a jeśli klasa T tworzy jakieś pomocnicze klasy R i w nich zapisuje wskaźnik do siebie, wskaźnik do rodzica :)

Oczywiście, że nie. Możesz mieć dziesięciokrotne dziedziczenie, a this będzie ten sam dla każdej klasy w hierarchii. Zresztą zobacz jak ten this wygląda od strony assemblera - najczęściej jest to wartość pobierana ze stosu (pierwszy parametr metody), a nie z obszaru pamięci zajmowanej przez klasę.

0

Chyba sie nie zrozumieliśmy ;-P
Dam przykład:

class Child { 
   Klasa *parent;
public:
   Child(Klasa *Parent): parent(Parent) {};
}

//...

Klasa::Klasa(const Klasa &K)
{
   /*...*/ new Child(this); //po zmianie lokalizacji Klasy (memcpy) wpis 'parent' w utworzonym tu obiekcie Child będzie błędny
}
0

W tym przypadku to oczywiste - trochę namotałeś z tym this :P W sumie zamiast przekazywać właściciela (tylko) w konstruktorze zrób metodę, która umożliwi Ci jego zmianę. Z drugiej strony, to dość ryzykowna konstrukcja - co się stanie jak Klasa zostanie zniszczona przed Child (zakładając, że klasa może istnieć poza właścicielem) ??? Przydałby się reference counting i (tylko) dynamiczne tworzenie właściciela.

0

To podałem tylko dla przykładu. Nie ja definiuje klase 'Klasa', jest to parametr szablonu.

Użycie operatora przypisania '=' prawie dwukrotnie spowolni funkje, no ale nic mi chyba innego nie zostaje, jeśli chce być zgodny ze standartem c++ ...

0

Użycie operatora przypisania '=' prawie dwukrotnie spowolni funkje

E tam spowolni... wszystko zależy od zastosowania funkcji/obiektu. Takie przejmowanie się - na zapas - wydajnościa nie ma sensu ;)

0

Przypadkiem znalazłem rozwiązanie problemu. Aby wywołać konstruktor (kopiujący, tworzący - nie ma znaczenia) na już przydzielonym obszarze pamięci wystarczy podać po new, w nawiasie, wskaźnik do tego obszaru :) np.

char obszar[sizeof(Klasa)];
klasa *p = new (obszar) Klasa;

Dziwne, że nikt nie wiedział :-D

Tylko trzeba pamiętać, że jeśli wywołamy

delete p;

to wywołujemy destruktor + free czyli tak jakby wywołać p->~Klasa();
free(obszar);

Jeśli obiekt *p byłby utworzony na początku jakiejś tablicy obiektów Klasa utworzonych w ten specyficzny sposób, to delete p zwolniłoby pamięć całej tablicy !!! W takich sytuacjach nie można używać delet p; tylko p->~Klasa();
0
adf88 napisał(a)

Dziwne, że nikt nie wiedział :-D

W sumie wiedział... ale nie pomyślał [wstyd]

1 użytkowników online, w tym zalogowanych: 0, gości: 1