Wprowadzam dwuwymiarowy kontener tablicy (np. boost::multi_array<T,2>
, głównie do ćwiczeń). Aby użyć notacji podwójnego indeksu (a[i][j]
), wprowadziłem klasę proxy row_view
(i const_row_view
, ale tutaj nie chodzi mi o stałą), która utrzymuje wskaźnik na początku i końcu wiersza.Ważność wskaźnika zwróconego przez operatora->
Chciałbym również, aby móc iteracyjne wierszy i ponad elementów w rzędzie oddzielnie:
matrix<double> m;
// fill m
for (row_view row : m) {
for (double& elem : row) {
// do something with elem
}
}
Teraz klasa matrix<T>::iterator
(która jest przeznaczona do iteracyjne nad rzędami) prowadzi prywatną row_view rv;
wewnętrznie śledzić wiersz, na który wskazuje iterator. Naturalnie iterator
realizuje również funkcje dereferenciation:
- dla
operator*()
, należałoby zazwyczaj chcą zwrócić odwołanie. Zamiast tego, tutaj odpowiednia rzecz wydaje się zwrócić wartośćrow_view
(tj. Zwrócić kopię prywatnegorow_view
). Zapewnia to, że gdy iterator jest zaawansowany,row_view
nadal wskazuje poprzedni wiersz. (W pewnym sensierow_view
działa jak referencja). dla
operator->()
, nie jestem tego taki pewien. Widzę dwie opcje:zwracają wskaźnik do prywatnej
row_view
z iteracyjnej:row_view operator->() const { return &rv; }
zwracają wskaźnik do nowego
row_view
(kopia prywatnej jeden). Ze względu na czas przechowywania, musiałoby to zostać przydzielone na stercie. W celu zapewnienia Clean-up, ja owinąć go wunique_ptr
:std::unique_ptr<row_view> operator->() const { return std::unique_ptr<row_view>(new row_view(rv)); }
Oczywiście, 2 jest bardziej poprawna. Jeśli iterator jest zaawansowany po wywołaniuoperator->
, zmieni się row_view
wskazany w 1. Jednak tylko w ten sposób mogę myśleć, gdzie byłoby to znaczenia, jeżeli jest operator->
został nazwany przez jego pełnej nazwy i zwrócony wskaźnik był związany:
matrix<double>::iterator it = m.begin();
row_view* row_ptr = it.operator->();
// row_ptr points to view to first row
++it;
// in version 1: row_ptr points to second row (unintended)
// in version 2: row_ptr still points to first row (intended)
jednak nie jest to w jaki sposób chcesz zazwyczaj korzystają operator->
. W takim przypadku należy prawdopodobnie zadzwonić pod numer operator*
i zachować odniesienie do pierwszego wiersza. Zwykle można by natychmiast użyć wskaźnika do wywołania funkcji składowej row_view
lub uzyskania dostępu do elementu, np. it->sum()
.
Moje pytanie teraz brzmi: Biorąc pod uwagę, że składnia ->
proponuje natychmiastowe użycie, to ważność wskaźnika zwracanego przez operator->
uważany jest ograniczona do takiej sytuacji, czy będzie bezpieczne konto wdrożenie do powyższej „nadużycie” ?
Oczywiście rozwiązanie 2 jest znacznie droższe, ponieważ wymaga przydziału sterty. Jest to oczywiście bardzo niepożądane, ponieważ dereferencja jest dość powszechnym zadaniem i nie ma takiej potrzeby: użycie unikatowej metody pozwala uniknąć takich problemów, ponieważ zwraca kopię przypisaną do stosu row_view
.
Jestem prawie pewny, że musisz zwrócić referencję dla 'operatora *' i wskaźnik dla 'operatora ->': https://stackoverflow.com/questions/37191290/iterator-overload-member-selection-vs -indirection-operator – NathanOliver
Według [cppreference] (http://en.cppreference.com/w/cpp/language/operators): "Przeciążenie operatora -> musi albo zwrócić surowy wskaźnik, albo zwrócić obiekt (przez odniesienie lub według wartości), dla których operator -> jest z kolei przeciążony. " – Jonas
Jeśli chodzi o 'operator *', nie znalazłem żadnych ograniczeń. Kompilator na pewno nie narzeka. – Jonas