Pointer to iterator II

8 listopada 2008

Kontynuując temat konwersji wskaźnika do iteratora z poprzedniej notki, chciałbym rzucić nieco więcej światła i nowych spostrzeżeń jakie mnie naszły po popełnieniu wspomnianego wpisu, po którym nie mogłem spokojnie zasnąć ;)

Rewidując ponownie ten problem pod katem wydajnościowym i nie tylko doszedłem do wniosku, że w ogóle taka operacja jest bez sensu, uzycie takiej operacji w kodzie to bad design. Tak, świadczy to o złym projekcie i należałoby się dobrze zastanowić co dalej zrobić.

Gdy mamy opcje: wskaźnik czy iterator, powinniśmy bez namysłu wybrać iterator i z niego korzystać. W sytuacji, gdzie jakiś powodów mamy sam wskaźnik, a potrzebnym nam jest iterator to należy pomyśleć o zmianie projektu lub umożliwić wykonanie danej usługi bezpośrednio na wskazywanym obiekcie, o ile oczywiście jest to możliwe do zrealizowania.

Do potwierdzenia bezsensowności rozważmy przedstawione w poprzedniej notce sposoby wyznaczania iteratora na podstawie wskaźnika przy wykorzystaniu algorytmy find i find_if z biblioteki standardowej, przy założeniu, że implementacja wykorzystuje wskaźniki wewnątrz iteratorów, a nasz wskaźnik wskazuje na istniejący w kontenerze element.

Końcowa wersja funkcji z find po wygenerowaniu i rozwiniecie kodu przez kompilator, mogłaby wyglądać następująco:

Obj* find(Obj* first, Obj* last, const Obj& val) {
 
	while (first != last && *first != val)
		++first;
	return first;
 
}

Jako argument val podajemy nasz wskaźnik, funkcja przechodzi przez wszystkie elementy do napotkania elementu na jaki wskazuje nasz wskaźnik, po czym zwraca ten sam wskaźnik.

W wyniku czego otrzymujemy wskaźnik, ten sam wskaźnik jaki mieliśmy, wiec nic nie otrzymaliśmy. Prócz wygenerowania zbędnego kodu i narzutu w czasie wykonania. Dodatkowo, prócz zbędnej pętli, której wykonanie rośnie liniowo ze wzrostem rozmiarów kontenera i dereferencjach w każdej iteracji, wykorzystywany jest operator porównania typu Obj, co przy „cięższym” typie może być trochę kosztowne.

Wersja z find_if będzie trochę lepsza:

Obj* find_if(Obj* first, Obj* last, const Obj* val) {
 
	while (first != last && first != val)
		++first;
	return first;
 
}

Tutaj tylko porównanie wskaźników, ale nadal wykonanie pętli jest zbędne, bo z góry znamy wynik.

Oczywiście sprawa wygląda całkiem inaczej, gdy wskaźnik nie wskazuje na żaden element kontenera tylko na inny obiekt, a my chcemy znaleźć wystąpienie tego elementu w kontenerze i otrzymać odpowiedni iterator.

W innym wypadku (konwersja) jest to czysta głupota, świadczącą o źle zaprojektowanym projekcie. Powinniśmy wystrzegać się takich bezsensownych operacji.

Dobrze, że w moim projekcie, łatwo da się rozwiązać problem wskaźnik -> iterator.

Podobne notatki:

Może zainteresują Cię również następujące, pododbne notatki:

Nikt jeszcze nie skomentował tego wpisu.
Możesz być pierwszy.

Dodaj swój komentarz

Możesz użyć tych tagów XHTML-a: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Jeśli chcesz wstawić kilku linijkowy fragment kodu, użyj tagów <pre lang="x"></pre> (gdzie x język kodu np. cpp, perl, html). W ten sposób kod zostanie odpowiednio sformatowany i pokolorowany przez system.

Uwaga!

Na tym blogu działa system cache oraz filtr antyspamowy. Twój komentarz może być widoczny na stronie z pewnym opóźnieniem. Proszę o cierpliwość. Jeśli utraciłeś już wszystkie jej zasoby poinformuj mnie o tym, być może system uznał Cię za spamera ;)