Zwracanie przez referencję

0

Witam
Mam krótkie pytanie, mam klasę vector przechowującą wskaźnik (jako dynamiczna tablica) i rozmiar tej tablicy i chcę stworzyć operator[]. Jako że zwraca on int& to mam pytanie, co zwrócić w sytuacji gdy odwołano się do nieistniejącego elementu tablicy? Tzn chciałbym napisać

int& vector::operator[](int index){
if(index<0 || index>=rozmiar) return ???;
else return tab[index];
}

Co zwrócić w przypadku gdy warunek w if jest spełniony żeby nie było to błędem?

I czy gdyby vector był szablonem klasy i operator zwracałby T&, to czy rozwiązanie byłoby takie samo?

1

osobiście uważam, że w takim wypadku dobrym rozwiązaniem będą wyjątki, zamiast zwracać losowy element, obiekt static. Tak samo lepiej przekazywać unsigned int, jako indeks. Przykład:

int& vector::operator[](unsigned int index)
{
	if(index >= size) throw std::out_of_range("out_of_range");

	return tab[index];
}
2

A najlepiej to size_t zamiast unsigned ;)

0

Tylko wtedy przy każdym wywołaniu operatora trzeba by dawac bloki try i catch? Tego chciałem uniknąć :d

3

W bibliotece standardowej przyjęto zasadę która jest zgodna z całą filozofią języka. W skrócie "przecież wiesz co robisz" :-). Stąd przy dostępie z użyciem operator[] nie są sprawdzane zakresy i uzyskując dostęp poza zakresem, masz zachowanie niezdefiniowane.

Jeśli chcesz mieć kontrolę przy dostępie, w wektorze stosujesz wywołanie at(). Wtedy jak jesteś poza zakresem, rzucany jest wyjątek out_of_range.

Jeśli jednak nie chcesz być zgodny z zapisem biblioteki standardowej, to rozważ użycie boost::optional http://www.boost.org/doc/libs/1_58_0/libs/optional/doc/html/index.html. Ogólnie ta biblioteka załatwia problem zwracania "magicznej wartości" jako sygnalizacji błędu.

2
alagner napisał(a):

A najlepiej to size_t zamiast unsigned ;)

oczywiście - masz rację. To był jedynie mały przykład i pomyślałem, że std::size_t może być słabo znany przez początkujących.

Besanouno napisał(a):

Tylko wtedy przy każdym wywołaniu operatora trzeba by dawac bloki try i catch? Tego chciałem uniknąć :d

jakie przy każdym wywołaniu operatora? Opatrzysz cały blok/bloki funkcji i z głowy. Przecież taka jest jedna z idei wyjątków, by uchronić Cię przy tego typu problemami. W przypadku zastosowania rady "zwróć magiczny obiekt/wartość" (funkcja zwraca referencję) to dopiero wtedy jesteś zmuszony sprawdzania wszędzie, za każdym razem, czy czasami Twój wektor nie zwrócił... błędu? Wyobraź sobie teraz ten kod.

można tutaj zadać jeszcze pytanie, co w Twoim przypadku może wyjść poza zakres wektora? Ty sam, w kodzie? Jeśli tak, to babranie się w obsługę własnych, tego typu, błędów logicznych nie ma sensu. Nie lepiej zastosować makro assert, a w wersji release je usunąć?

int& vector::operator[](unsigned int index)
{
    assert(index < size);
 
    return tab[index];
}
0

Też uważam że sprawdzanie nie bardzo ma sens skoro używam tego sam, ale raz już mi prowadzący odjął punkty za niesprawdzenie w takim operatorze który zwracał wartość, a nie referencję... ;p
W takim wypadku najlepiej będzie chyba wyrzucić wyjątek. Dziękuję za odpowiedzi ;)

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