tablica dynamicznie zmieniajaca rozmiar

0

Prosta dynamiczna tablica (na wskaźniki obiektów)
Czy ktoś mi podpowie, gdzie jest błąd?

//---------------------------------------------------------------------------
#ifndef pointer_arrayH
#define pointer_arrayH
//---------------------------------------------------------------------------
//#define TEST
//#include <stdexcept>
//#include <iostream>


//---------------------------------------------------------------------------
namespace mylib {

	//----------------------------------------------------------------------
	template <typename T, unsigned N = 10>
	class pointer_array_type
	{
		// SKLADNIKI PRYWATNE ----------------------------
		typedef T* pointer_type;
		// static constans
		static const unsigned static_size = N;
		// pointer
		pointer_type temp;

		typedef struct
		{
			bool aktywna;
			unsigned rozmiar;
			unsigned kolejny_index;
			pointer_type* ptr;
		} array_type;

		array_type tablica_A;
		array_type tablica_B;
		array_type* adres;

		// SKLADOWE FUNKCJE PRYWATNE ---------------------
	     bool aktualizuj_tablice(int przyrost);
		bool range_check (unsigned index)
               {return index < adres->kolejny_index ? true : false; }

       public:
		// KONSTRUKTOR I DESTRUKTOR ----------------------
	     pointer_array_type(void);
		~pointer_array_type(void);

		// FUNKCJE DOSTEPU -------------------------------
          unsigned Add(pointer_type pointer);
		pointer_type Item(int index);
          bool Erase(int index);
		int Size(void);
          void Clear(void);

          // front() and back()
		pointer_type Front() {return adres->ptr[0];}
          pointer_type Back() {return adres->ptr[adres->kolejny_index - 1];}

          // przypisz jedna wartosc wszystkim elementom
		void assign(pointer_type pointer)
          {
			for(unsigned i = 0; i < adres->rozmiar; i++)
                    adres->ptr[i] = pointer;
		}
     };

     // AKTUALIZUJ_TABLICE --------------------------------------------------
	template <typename T, unsigned N>
     bool pointer_array_type<T, N>::aktualizuj_tablice(int przyrost)
	{
          // jesli tablica 'A' jest aktywna
		if(tablica_A.aktywna)
     	{
			#ifdef TEST
                     //std::cout << " f: atualizuj_tablice() - aktywacja tablicy B \n";
			#endif

			//------------------------------------------------------------
               // nowy rozmiar tablicy
			int count = przyrost + tablica_A.rozmiar;

			// tworzymy dynamicznie nowa tablice krotek, o nowym
     		// rozmiarze, jesli zabraknie pamieci, adres przyjmie
			// wartosc 0
     		tablica_B.ptr = new pointer_type[count];

     		// jesli zabraklo pamieci wypisz komunikat, powroc do
			// poprzedniego rozmiaru tablicy aktywnej i zwroc 'false'
     		if(tablica_B.ptr == 0)
			{
                    tablica_B.rozmiar -= przyrost;
				return false;
               }
			// nowy rozmiar tablicy
     		tablica_B.rozmiar = count;
			// ustaw tablica 'B' jako aktywna
     		tablica_B.aktywna = true;
			// kopiuj liczbe krotek
     		tablica_B.kolejny_index = tablica_A.kolejny_index;

     		// przekopiuj pola krotek do odpowiednich krotek nowej tablicy
			// a poprzednia komorke wyzeruj (wyzeruj adres), wykorzystywany
     		// domyslny operator przypisania
			count = tablica_A.kolejny_index;
     		for(int i = 0; i < count; i++)
				tablica_B.ptr[i] = tablica_A.ptr[i];

			// zwolnij pamiec
               delete [] tablica_A.ptr;
			// ustaw tablice 'A' jako nieaktywna
               tablica_A.aktywna = false;
			// wyzeruj wartosci
               tablica_A.kolejny_index = 0;
			tablica_A.rozmiar = 0;
               tablica_A.ptr = 0;

               // ustaw adres pomocniczy na aktywna tablice
			adres = &tablica_B;

			return true;
     	}

     	// analogicznie, jesli tablica 'B' jest aktywna
		if(tablica_B.aktywna)
     	{
			#ifdef TEST
                     //std::cout << " f: atualizuj_tablice() - aktywacja tablicy A \n";
			#endif

			//------------------------------------------------------------
     		int count = przyrost + tablica_B.rozmiar;

     		tablica_A.ptr = new pointer_type[count];

     		if(tablica_A.ptr == 0)
			{
                    tablica_A.rozmiar -= przyrost;
				return false;
               }
			tablica_A.rozmiar = count;
     		tablica_A.aktywna = true;
			tablica_A.kolejny_index = tablica_B.kolejny_index;
     		count = tablica_B.kolejny_index;
			for(int i = 0; i < count; i++)
               	tablica_A.ptr[i] = tablica_B.ptr[i];

               delete [] tablica_B.ptr;
			tablica_B.aktywna = false;
               tablica_B.kolejny_index = 0;
			tablica_B.rozmiar = 0;
               tablica_B.ptr = 0;

               adres = &tablica_A;
		}

		return true;
     }

     // KONSTRUKTOR ---------------------------------------------------------
	template <typename T, unsigned N>
     pointer_array_type<T, N>::pointer_array_type(void)
	{
          #ifdef TEST
			// std::cout << " f: konstruktor() \n";
          #endif

          //-----------------------------------------------------------------
		// ustanawiamy tablice 'A' za aktywna
          tablica_A.aktywna = true;
		tablica_A.kolejny_index = 0;
          tablica_A.rozmiar = static_size;
		tablica_A.ptr = new pointer_type[static_size];
          // ustaw adres pomocniczy na powyzsza (aktywna) tablice
		adres = &tablica_A;
          assign(0);
		// tablice 'B' za nieaktywna
          tablica_B.aktywna = false;
		tablica_B.kolejny_index = 0;
          tablica_B.rozmiar = 0;
		tablica_B.ptr = 0;
     }

     // DESTRUKTOR ----------------------------------------------------------
	template <typename T, unsigned N>
     pointer_array_type<T, N>::~pointer_array_type(void)
	{
          #ifdef TEST
			// std::cout << " f: destruktor() \n";
          #endif

          //-----------------------------------------------------------------
		for(unsigned i = 0; i < adres->kolejny_index; i++)
               if(adres->ptr[i])
				delete adres->ptr[i];

		delete [] adres->ptr;
     }

     // ADD -----------------------------------------------------------------
	template <typename T, unsigned N>
     inline unsigned pointer_array_type<T, N>::Add(T* pointer)
	{
          // sprawdz, czy jest jeszcze 'wolna komorka'
		if(adres->kolejny_index == adres->rozmiar)
               // jesli nie ma, powieksz tablice o wartosc
			if(!aktualizuj_tablice(static_size))
                    // jesli nie udalo sie powiekszyc, wroc
				return -1;

		adres->ptr[adres->kolejny_index] = pointer;

		// powieksz index o 1
          adres->kolejny_index++;

          #ifdef TEST
			//std::cout << " f: add() size = " << adres->ptr[size() - 1] << "\n";
          #endif
		//-----------------------------------------------------------------

		return (adres->kolejny_index - 1);
     }

     // ITEM ----------------------------------------------------------------
	template <typename T, unsigned N>
     inline T* pointer_array_type<T, N>::Item(int index)
	{
          #ifdef TEST
			//std::cout << " f: Item() ";
          #endif
		//-----------------------------------------------------------------

		if(!range_check(index))
               return temp;

          return adres->ptr[index];
	}

	// ERASE ---------------------------------------------------------------
     template <typename T, unsigned N>
	inline bool pointer_array_type<T, N>::Erase(int index)
     {
		if(!range_check(index))
               return false;

          delete adres->ptr[index];
		for(int i = index; i < adres->kolejny_index; i++)
     		adres->ptr[i] = adres->ptr[i + 1];
		adres->kolejny_index--;

		#ifdef TEST
               // std::cout << " f: erase() " << size() << "\n";
		#endif

		//-----------------------------------------------------------------
     	if((adres->rozmiar - adres->kolejny_index) >= static_size)
			aktualizuj_tablice((-1) * static_size);
          return true;
	}

	// SIZE ----------------------------------------------------------------
     template <typename T, unsigned N>
	int pointer_array_type<T, N>::Size(void)
     {
		return adres->kolejny_index;
     }

     // CLEAR ---------------------------------------------------------------
template <typename T, unsigned N>
     inline void pointer_array_type<T, N>::Clear(void)
	{
          int count = adres->kolejny_index;
		for(int i = count - 1; i >= 0; i--)
               Erase(i);
	}

//---------------------------------------------------------------------------
}; // end of namespace mylib

//---------------------------------------------------------------------------
#endif
0

Może konkretńej? Co wypluwa kompilator? Czemu uważasz, że jest tutaj błąd?

0
//---------------------------------------------------------------------------
#include <iostream>
#pragma hdrstop
#include "dynamic_array.h"

class TKlasaA{};
class TKlasaB{};
//---------------------------------------------------------------------------

#pragma argsused
int main(int argc, char* argv[])
{
	{
		mylib::pointer_array_type<TKlasaA> listA;
		mylib::pointer_array_type<TKlasaB> listB;
	}

	std::cin.get();
	return 0;
}
//---------------------------------------------------------------------------

Komunikat:
[BCC32 Error] dynamic_array.h(170): E2034 Cannot convert 'TKlasaB * *' to 'TKlasaA * *'

Wiem dlaczego wyskakuje, jak temu zaradzić? Czy deklarować strukturę array_type globalnie?
(jeśli zadeklarujemy globalnie, jest O.K.)
Czy jest jakaś inny sposób? Wolałbym, wygodniej byłoby, gdyby była składową.</cpp>

0

Więc może udostępnię kod wersji, która działa bez zarzutu.
Jest to klasa szablonowa prostego kontenera tablicowego
bez stosowania iteratorów. Domyślny rozmiar (tutaj 10) można
zmienić. Pomysł polega na utworzeniu dwóch egzemplarzy
klasy pomocniczej pointer_dynamic_array, których składnikiem jest
między innymi roboczy wskaźnik ptr będący początkiem
tworzonej dynamicznie tablicy. Tablice te tworzone i likwidowane
są na przemian. A wartości przechowywanych adresów są
przekopiowane. Chodzi o to, aby nie stosować zewnętrznej
klasy pointer_dynamic_array lecz jakąś składową, schowaną
strukturę.
Tak jest w pierwszej podanej wersji, błąd ujawnia
się w chwili konkretyzacji szablonu.
Nic mi do głowy nie przychodzi.

//q: CIACH. wklejony kod byl identyczny z tym z pierwszego postu

0

A czemu nie skorzystasz np. z std::vector ?

0

Sprawa się już wyjaśniła. Spośród kompilatorów którymi sprawdzałem
kod, jedynie najnowszy kompilator Borlanda, którego aktualnie używam,
nie akceptuje tego rozwiązania.

0

skompilowanie kodu zamieszczonego w poscie nr1 oraz maina z kolejnego postu pod g++ version 3.3.6 rzeczywiscie nie daje bledow.. o co w koncu chodzi(ło)?

piotr.wycz napisał(a)

Więc może udostępnię kod wersji, która działa bez zarzutu (...)

wg. mojego diff'a, kod pliku .h z pierwszego postu i z kolejnego sa identyczne. po co bylo wklejac drugi raz?

                     tablica_B.ptr = new pointer_type[count];

                     // jesli zabraklo pamieci wypisz komunikat, powroc do
                        // poprzedniego rozmiaru tablicy aktywnej i zwroc 'false'
                     if(tablica_B.ptr == 0)

drobna uwaga: new nie zwraca wartosci zero, tylko rzuca wyjatek bad_alloc

edit: i drobne pytanie - czy ta żonglerka tablicą-aktywną i tablicą-zamiennikiem ma jakieś głębsze podłoże czy jest tylko jedynie wprawką programistyczną w temacie template'ow lub implementacją wyśnionego pomysłu tak ot z czystej ciekawosci? generalnie nie widzę żadnego większego sensu w utrzymywaniu tabA/tabB.. spokojnie wystarczy jedno tab a cale operowanie 'pomocniczą' tabelą można sprowadzić do tymczasowej tmpTab w tworzonej na biezaco w ktorejs z metod.. ilosc kodu zmniejsyz Ci sie o circa polowe.. zreszta, nawet jesli upierac sie przy takim ukladzie ---- pisanie if(tabA.aktywna) do ... else if(tabB.aktywna) do-the-same jest bezcelowe.. wlasnie na takie przypadki wydziela sie metody prywatne --- doSomething(tabOne*, tabTwo*) -- i wywolujesz na odpowiednio doSomething(tabA,tabB) lub doSomething(tabB, tabA).. copy&paste&replace jest prawie zawsze 'ZUE' i utrudnia utrzymanie

0

To był program dla studenta. Chodziło o wykonanie tablicy na wskaźniki do typów definiowanych,
które to typy miały być likwidowane wraz z tą tablicą. Faktem jest, że jest dużo kodu, zastanawiałem
się jak to rozwiązać i ostatecznie takie rozwiązanie przyjąłem.
Ale generalnie nie o to chodzi.

Mamy przykładowy kod:

//---------------------------------------------
#include <iostream>
#include <vcl.h>
#pragma hdrstop
using namespace std;
//---------------------------------------------
template <typename T, unsigned N = 10>
class TTablica
{
  private:
	typedef T* pointer_type;
	typedef struct
	{
		pointer_type* ptr;
	} tablica_type;
	tablica_type tablica;

  public:
	TTablica(void)
	{
		tablica.ptr = new pointer_type[N];
	}
	~TTablica(void)
	{
		delete [] tablica.ptr;
	}
};
//----------------------------------------------
class TKlasaA;
class TKlasaB;
//----------------------------------------------
int main(int argc, char* argv[])
{
	{
	    TTablica<TKlasaA> TA;
	    TTablica<TKlasaB> TB;
	}

	system("pause");
	return 0;
}
//-----------------------------------------------

Kompilator Borlanda /najnowszy/ tego nie akceptuje, pytałem nawet na usenecie, nikt nie wie.

0

a jak brzmi blad? tak jak wczesniej, ze cannot convert TKlasaA* to TKlasaB* ?

jedyne co widze co moze miec jakikolwiek wplyw, to to, że:

typedef T* pointer_type;
        typedef struct
        {
                pointer_type* ptr;
        } tablica_type;

jako ze jest to wewnatrz definicji template'a, to zarowno pointer_type jak i tablica_type są symbolami zaleznymi (dependent)..

stad, byc moze Borland wymaga, aby explicite to zaznaczac, zwlaszcza wewnatrz tablica_type:

typedef T* pointer_type;
        typedef struct
        {
                typename TTablica<T,N>::pointer_type* ptr;
        } tablica_type;

wyjasnienie: tablica_type jest deklaracja NOWEJ klasy zanim jej nad/klasa zostala do konca sparsowana. mozliwe jest ze kompilator nie do konca jest w takim przypadku w stanie okreslic jaki symbol do jakiego scope'a nalezy - badz co badz pointer_type pochodzi ze scope'a wyzej - ktory jeszcze byc moze nie zostal calkiem sparsowany [wszystkie byc-moze zaleza od tego jak napisano parser kodu w borlandzie]

sprobuj, a nuż..

jesli borlandowi o to chodzilo --- to w dodatku by to wskazywalo, ze wewnatrz kompilatora jest bug i po pierwszej specjalizacji szablonu symbol pointer_type zostal zwiazany z TKlasaA* i przy drugiej specjalizacji T!=pointer_type i stad blad w linijce tablica.ptr = new pointer_type[N];
(a przy II specjalizacji powinien zaczac na czysto, ew. powiedziec ze symbol juz jest zdefiniowany..)

..ale to by bylo arcyciekawe :)

0

Dziękuję za podpowiedź, ale nie dało to pozytywnego rozwiązania.
Jakieś pewnie istnieje ale teraz nie mam czasu go szukać.

Z resztą każdy, kto ma do czynienia ze środowiskiem C++Builder zauważa
jego pewne osobliwostki. Np. ostatnio co 'odkryłem' i co mnie pozytywnie
zaskoczyło to to, że kompilator Borlanda akceptuje poniższy kod a większość
innych kompilatorów nie.

#include <vector>
template <typename T>
class TKontener
{
    typedef std::vector<T> kontener_type;
    typedef kontener_type::iterator iterator_type;
    iterator_type iter;
};
0

ad 1)
Borland mnie rozwalił - głuptakowi nie pasowało:

typedef struct
{
    pointer_type* ptr;
} tablica_type;

no dobrze, niech będzie, że jest jest to taka "nieczysta" deklaracja (typedefowanie struktury anonimowej...), więc błędu jakiegoś można się spodziewać, ale nie takiego :) Co naprawia problem? Podanie pełnej deklaracji w stylu C:

typedef struct _dowolna_nazwa
{
    pointer_type* ptr;
} tablica_type;

albo czystej deklaracji w stylu C++:

struct tablica_type
{
    pointer_type* ptr;
};

ad 2)
czyli mamy konstrukcję:

typedef klasa<zalezna>::nazwa xxx

w zasadzie to Borland z jednej strony cieszy, bo przecież jesteśmy w typedef, oczywistym jest, że wszystko dotyczy typów, fajnie że się domyśla.

z drugiej strony, to niepokoi, bo zasada uniwersalna mówi: kompilator ma domyślnie traktować nazwa jako składową statyczną (a więc zmienną). Dopiero po jawnym podaniu typename ma przyjąć, że o typach mówimy. Brzydko, że Borland się wyłamuje, bo w szablonach i tak jest dość niejednoznaczności często, nie trzeba nam jeszcze wyjątków i kompilatorów mądrzejszych niż ustawa (pardon: standard) przewiduje.

prawidłowo powinno być tak (zapis akceptowany przez wszystkich, Borlanda też):

#include <vector>
template <typename T>
class TKontener
{
	typedef std::vector<T> kontener_type;
	typedef typename kontener_type::iterator iterator_type;
	iterator_type iter;
};
0

Np. ostatnio co 'odkryłem' i co mnie pozytywnie
zaskoczyło to to, że kompilator Borlanda akceptuje poniższy kod a większość
innych kompilatorów nie.

bo to jest wlasnie to, o czym mowilem: dependent typenames.. jesli puscil to bez typename, to chyba jednak maja drobne problemy z logika, jak to ladnie opowiedzial już Ranides :)

Ranides napisał(a)

ad 1)

wow.. to mnie tylko utwierdza w przekonaniu: byle jak najdalej od borlanda..

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