Własny kontener - ocena kodu

0

Witam, postanowiłem napisać własny kontener na dane. Wiem że jest STL itd. ale chciałem się czegoś nauczyć bo przy pisaniu takiego kontenera wykorzystuje się wiele (częściej lub rzadziej używanych) mechanizmów C++. Na ile to co stworzyłem przypomina std::vector z STLa? Wiem że pewnie nie jest to szczyt optymalizacji i brakuje "paru" metod, ale to dopiero początek i chcę wiedzieć czy idę w dobrym kierunku.

http://wklej.org/id/1229619/

Pzdr

0

Na oko nie jest źle, ale to:

	T & operator()(unsigned index) 
	{ 
		try 
		{
			if(index >= length) {
				throw("IndexOfBoundsException");		
			} else {
				return container[index];
			}
		} catch(const char * e) {
			std::cout<<e<<std::endl;
		}
	}

To jakis turbo WTF. Rozumiem że wypisanie błędu po prostu było za mało hakerskie i trzeba było rzucać "wyjątkiem"? ;]

1

Niewiele wspólnego. Inny interfejs, kompletnie inna wydajność. Mnóstwo UB. Nieprzewidziane sytuacje.

ms_array<unsigned> arr(1);
arr(0) = 1;
unsigned x = 0;
arr.remove(x); // które remove zostanie wywołane?
{
	my_arr<int> a;
} // destruktor woła delete[] niezaincjalizowanego wskaźnika ⟶ UB

Brak zdefiniowanych operatorów= i konstruktorów kopiujących (oraz move). Polecam poczytanie o "the rule of three" (ew 5 lub 0)

{
	my_arr<int> a(1);
	my_arr<int> b = a; // a.container == b.container
}

Każda zmiana pociąga za sobą realokację i przeniesienie całości kontenera. Fuj.

To tak na szybko.

0

@Shalom, no tak ten wyjątek to faktycznie fail... :D

Brak zdefiniowanych operatorów= i konstruktorów kopiujących (oraz move).

To wersja uboga jest więc jeszcze nie ma takich ficzerów :)

destruktor woła delete[] niezaincjalizowanego wskaźnika ⟶ UB

Słuszna uwaga.

Mnóstwo UB

Urząd Bezpieczeństwa? Rozumiem chodzi o błędy? Pokazałeś jeden :)

Każda zmiana pociąga za sobą realokację i przeniesienie całości kontenera. Fuj.

A jak inaczej powiększyć tablicę jeżeli nie realokować?

0

UB = undefined behaviour. W skrócie, od momentu jego wywołania nie możesz zagwarantować jakiegokolwiek działania programu (humorystycznie mówi się, że kompilator ma w tym momencie prawo wygenerować kod formatujący dysk). Pokazałem dwa takie przypadki oraz przypadek wołania innego przeładowania funkcji niż miałeś zamiar.

Jeśli chodzi o realokacje, to std::vector nie bez kozery amortyzuje koszt dodania nowego elementu. Ale nawet bez tego mogłeś użyć trójki funkcji malloc/realloc/free.

0

Ok, nie myslalem ze vector uzywa funkcji rodem z C. Co do funkcji remove ona usuwa po indeksie lub referencji, nie ma jeszcze opcji usuwania wystapien tak jak pokazales. Musze to przerobic. Dzieki.

0
if(c == value) return true; return false;

Mozesz zwyczajnie return c==value
klasa std::vector alokuje dwa razy więcej pamięci, niż faktycznie potrzeba. Właśnie po to, zeby nie kopiować całości przy dodawaniu elementów. Jeśli nie wystarczy miejsca, podwajany jest rozmiar wektora i kopiowany. Możesz wykorzystać tez węzły, jak kontener typu lista, ale domyślam się, że nie o to chodzi.

2

Na ile to co stworzyłem przypomina std::vector z STLa?

STL stosuje pewne konwencje, dzięki którym ze wszystkich kontenerów korzysta się podobnie, i ładnie się wszystko integruje.
Nie jest jednak łatwo zachować kompatybilność z STL-em, więc może na razie udawanie STL-a odłóż.

A jak inaczej powiększyć tablicę jeżeli nie realokować?

Realokować, ale nie za każdym razem. Najczęściej robi się tak, że gdy brakuje miejsca, powiększa się kontener dwukrotnie.
Taki nadmiar może przerażać, ale dzięki temu im większy kontener (a więc więcej danych do skopiowania) tym rzadsza jest relokacja.

Potrzebujesz więc dwóch „rozmiarów”: ilość elementów w kontenerze i ilość miejsca.

Szybko też dojdziesz do wniosku, że new-copy-delete elementów to zła droga, bo jeżeli klasa którą będziesz chciał trzymać w kontenerze będzie miała konstruktora i destruktora, to będą się radośnie wykonywać za każdą relokacją danych – a jeśli to będzie klasa reprezentująca otwarty plik, albo połączenie z bazą danych, to będzie bardzo źle.

Dlatego lepsze będzie malloc, realloc i free, oraz ręczne wywoływanie konstruktora i destruktora (poczytaj o placement new) tylko podczas dodawania i usuwania elementu.

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