Jestem całkiem nowy w C ++, więc podczas nauki staram się projektować z dużą ilością Java-izmów. W każdym razie w Javie, gdybym miał klasę z metodą „wyszukiwania”, która zwróciłaby obiekt T
z obiektu Collection< T >
pasującego do określonego parametru, zwróciłbym ten obiekt i gdyby obiekt nie został znaleziony w kolekcji, wróciłbym null
. Wtedy w mojej funkcji wywoływania po prostu sprawdzałbymif(tResult != null) { ... }
W C ++ dowiaduję się, że nie mogę zwrócić null
wartości, jeśli obiekt nie istnieje. Chcę tylko zwrócić „wskaźnik” typu T, który powiadamia funkcję wywołującą, że nie znaleziono żadnego obiektu. Nie chcę rzucać wyjątku, ponieważ tak naprawdę nie jest to wyjątkowa okoliczność.
Tak wygląda teraz mój kod:
class Node {
Attr& getAttribute(const string& attribute_name) const {
//search collection
//if found at i
return attributes[i];
//if not found
return NULL; // what should this be?
}
private:
vector<Attr> attributes;
}
Jak mogę to zmienić, żeby dać taki marker?
źródło
std::find(first, last, value)
zwraca,last
jeśli żaden element nie pasuje.Odpowiedzi:
W C ++ odwołania nie mogą mieć wartości null. Jeśli chcesz opcjonalnie zwrócić wartość null, jeśli nic nie zostanie znalezione, musisz zwrócić wskaźnik, a nie referencję:
Attr *getAttribute(const string& attribute_name) const { //search collection //if found at i return &attributes[i]; //if not found return nullptr; }
W przeciwnym razie, jeśli nalegasz na zwrócenie przez odwołanie, powinieneś zgłosić wyjątek, jeśli atrybut nie zostanie znaleziony.
(Nawiasem mówiąc, trochę się martwię, że twoja metoda jest
const
i zwraca wartość niebędącąconst
atrybutem. Ze względów filozoficznych sugerowałbym powrótconst Attr *
. Jeśli chcesz również zmodyfikować ten atrybut, możesz przeciążać inną niżconst
metodę zwracając równieżconst
atrybut niebędący atrybutem).źródło
nullptr
zamiastNULL
c ++ 11?Istnieje kilka możliwych odpowiedzi. Chcesz zwrócić coś, co może istnieć. Oto kilka opcji, od mojej najmniej preferowanej do najbardziej preferowanej:
Powrót przez odniesienie i wyjątek nie może znaleźć sygnału.
Attr& getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found throw no_such_attribute_error; }
Jest prawdopodobne, że brak znalezienia atrybutów jest normalną częścią wykonania i dlatego nie jest wyjątkowy. Obsługa tego byłaby głośna. Nie można zwrócić wartości null, ponieważ jest to niezdefiniowane zachowanie, które zawiera odwołania o wartości null.
Powrót przez wskaźnik
Attr* getAttribute(const string& attribute_name) const { //search collection //if found at i return &attributes[i]; //if not found return nullptr; }
Łatwo zapomnieć o sprawdzeniu, czy wynik z getAttribute byłby wskaźnikiem innym niż NULL i jest łatwym źródłem błędów.
Użyj Boost.Optional
boost::optional<Attr&> getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found return boost::optional<Attr&>(); }
A boost :: optional wskazuje dokładnie, co się tutaj dzieje i ma proste metody sprawdzania, czy taki atrybut został znaleziony.
Nota boczna: std :: optional był ostatnio głosowany w C ++ 17, więc będzie to "standardowa" rzecz w najbliższej przyszłości.
źródło
boost::optional
nie wiąże się z dużym narzutem (brak alokacji dynamicznej), dlatego jest tak wspaniały. Używanie go z wartościami polimorficznymi wymaga zawijania odwołań lub wskaźników.Możesz łatwo utworzyć obiekt statyczny, który reprezentuje wartość NULL.
class Attr; extern Attr AttrNull; class Node { .... Attr& getAttribute(const string& attribute_name) const { //search collection //if found at i return attributes[i]; //if not found return AttrNull; } bool IsNull(const Attr& test) const { return &test == &AttrNull; } private: vector<Attr> attributes; };
I gdzieś w pliku źródłowym:
static Attr AttrNull;
źródło
Jeśli chcesz
NULL
zwracać wartość, musisz użyć wskaźników zamiast odwołań.Referencje same w sobie nie mogą być
NULL
.(Uwaga do przyszłych plakatów z komentarzami: Tak, możesz ustawić adres odniesienia na NULL, jeśli naprawdę naprawdę spróbujesz).
Zobacz moją odpowiedź tutaj, aby zapoznać się z listą różnic między odniesieniami a wskaźnikami .
źródło
Jak już się zorientowałeś, nie możesz tego zrobić tak, jak zrobiłeś to w Javie (lub C #). Oto kolejna sugestia, którą możesz przekazać jako odwołanie do obiektu jako argument i zwrócić wartość bool. Jeśli wynik zostanie znaleziony w Twojej kolekcji, możesz przypisać go do przekazywanego odwołania i zwrócić „true”, w przeciwnym razie zwrócić „false”. Proszę wziąć pod uwagę ten kod.
typedef std::map<string, Operator> OPERATORS_MAP; bool OperatorList::tryGetOperator(string token, Operator& op) { bool val = false; OPERATORS_MAP::iterator it = m_operators.find(token); if (it != m_operators.end()) { op = it->second; val = true; } return val; }
Powyższa funkcja musi znaleźć operatora w kluczu „token”, jeśli znajdzie ten, który zwraca true i przypisać wartość do parametru Operator & op.
Kod dzwoniącego dla tej procedury wygląda następująco
Operator opr; if (OperatorList::tryGetOperator(strOperator, opr)) { //Do something here if true is returned. }
źródło
Powodem, dla którego nie możesz zwrócić tutaj wartości NULL, jest to, że zadeklarowałeś swój typ zwrotu jako
Attr&
. Końcówka&
sprawia, że zwracana wartość jest „referencją”, która jest w zasadzie gwarantowanym wskaźnikiem, który nie jest zerowy, do istniejącego obiektu. Jeśli chcesz mieć możliwość zwrócenia wartości null, zmieńAttr&
naAttr*
.źródło
Nie możesz zwrócić,
NULL
ponieważ typ zwracany funkcji jest obiektem,reference
a nie plikiempointer
.źródło
Możesz spróbować tego:
return &Type();
źródło