wskaźniki nieobowiązkowe vs. odniesienia nie-stałe w C ++

12

W Inne funkcje C ++, Argumenty referencyjne z Google C ++ Style Guide , czytałem, że odniesienia const nie może być używany.

Wszystkie parametry przekazane przez odwołanie muszą być oznaczone jako const.

Oczywiste jest, że patrzenie na wywołania funkcji, które używają referencji jako argumentów, jest absolutnie mylące dla programistów C, ale C i C ++ są teraz różnymi językami. Jeśli wymagany jest parametr wyjściowy , użycie wskaźnika dla wymaganego parametru wyjściowego może spowodować pominięcie całego ciała funkcji, co komplikuje implementację funkcji (formalnie zwiększa złożoność cykliczną i głębokość funkcji).

Chciałbym, aby kod C ++ był tak łatwy do zrozumienia / utrzymania, jak to możliwe, więc ogólnie jestem zainteresowany czytaniem przewodników po stylu kodowania. Ale jeśli chodzi o dostosowanie najlepszych praktyk w zespole, uważam, że zrozumienie uzasadnienia elementów przewodnika po stylu jest ważnym czynnikiem.

Czy odniesienia non-const naprawdę są tak złe? Czy banowanie ich dotyczy tylko Google, czy jest to powszechnie akceptowana zasada? Co uzasadnia dodatkowy wysiłek związany z implementacją parametrów wyjściowych jako wskaźników?

Wilk
źródło
2
„użycie do tego wskaźnika powoduje pominięcie całego ciała funkcji”, co?
maniak zapadkowy
@ratchetfreak Próbowałem to wyjaśnić. Przyznaję, że takie funkcje mogą wykazywać pewne wady projektowe. Wskaźnik jest zawsze formalnie opcjonalny, dlatego należy go sprawdzić przed usunięciem z niego odwołania.
Wolf,
4
Przewodnik po stylu C ++ firmy Google jest dość zacofany. Moim subiektywnym zdaniem należy go spalić.
Siyuan Ren,
Jeśli chodzi o ten konkretny element, myślę, że uzasadnienie polega na tym, że zmuszanie programistów do napisania znaku handlowego i, gdy argumenty mogą być zmutowane, pokazuje wyraźniejsze zamiary.
Siyuan Ren,
4
Przewodnik po stylu Google został napisany w niezmienionej formie, aby wspierać jednorodny kod w starszych projektach Google. Jeśli nie pracujesz nad starszymi projektami (które zostały napisane z tym przewodnikiem stylu od samego początku), prawdopodobnie nie powinieneś go używać (określa wiele reguł, które nie są dobre dla nowego kodu (c ++ 11, c ++ 14 , c ++ 17)).
utnapistim

Odpowiedzi:

18

Uzasadnieniem przewodnika po stylu Google jest po prostu wyjaśnienie ze strony wywołania funkcji, czy parametr jest parametrem wejściowym czy wyjściowym. (Zobacz tutaj, aby uzyskać dalszą dyskusję.) Inne języki wyraźnie określają parametry według projektu; Na przykład C # ma outsłowo kluczowe, które musi być użyte w witrynie połączenia . Ponieważ C ++ nie wyraża tego wyraźnie, Google zdecydował się na użycie const ref. kontra wskaźnik, aby było jasne.

Czy to tylko reguła Google? Nie, ale wątpię, czy to bardzo rozpowszechnione. Nie sądzę, że widziałem go poza przewodnikiem po stylu Google i grupami, które wyraźnie stosują się do części przewodnika po stylu Google. (Na przykład spodobał mi się ten pomysł, kiedy po raz pierwszy przeczytałem przewodnik po stylu Google lata temu i użyłem go do mojego własnego kodu).

W szczególności nowo ogłoszone podstawowe wytyczne C ++ wolą wartości zwracane od parametrów wyjściowych dla (prawie) wszystkiego, a dla pozostałych używa referencji non-const. Użycie wskaźników i referencji przez Google może sprawić, że parametry wyjściowe będą wyraźniejsze, ale zwracane wartości będą jeszcze wyraźniejsze. Teraz, gdy C ++ 11 ma znormalizowane ruchy (wartości referencyjne, &&aby zwroty wielu typów były tanie) i krotki (pozwalające w łatwy sposób zwrócić wiele wartości), wiele przypadków użycia parametrów out nie ma już zastosowania.

Wytyczne C ++ Core mają za sobą kilka wielkich nazwisk (Bjarne Stroustrup, Herb Sutter), są obsługiwane przez Microsoft i obejmują najnowsze funkcje C ++ (w przeciwieństwie do przewodnika po stylu Google), więc spodziewam się, że jego rekomendacje będą bardziej popularne niż Google.

Josh Kelley
źródło
Dzięki za odpowiedź (również za krótką wycieczkę do C #). Łatwe recenzowanie jest oczywiście ważnym punktem, szczególnie w projektach Open Source. W przypadku tanich zwrotów we współczesnym języku C ++ rozważania te stracą na znaczeniu. W przypadku starszych starszych programów i przestarzałych kompilatorów może być nadal pomocne.
Wolf
Nie zapomniałem o tym, ale podstawowe wytyczne C ++ nie są tak szybkie. Interesujące jest to, że jego filozofia pokazuje uzasadnienie reguł, a także zmodernizowany pogląd na programowanie („Wyrażanie pomysłów bezpośrednio w kodzie” przypomina trochę Zen z python) jako sposób komunikacji.
Wolf,
Suplement: bezpośredni link do sekcji Filozofia Wytycznych Kodeksu C ++.
Wilk
1

Istnieją 2 opcje postępowania z przekazanym nieprawidłowym wskaźnikiem, pierwszym sprawdzeniem i wczesnym powrotem lub pozostawieniem niezdefiniowanego zachowania (jeśli zależy Ci bardziej na szybkości niż solidności).

Sprawdzanie jest tak proste jak:

void foo(void* buffer){
    if(buffer == nullptr)
        return;

    //actually foo

    // note no increase in indentation required

}

Ten rodzaj kontroli jest ogólnie akceptowany jako kontrola parametrów. Jeśli zobaczysz kod, jest całkiem jasne, że oczekujesz, że wskaźnik o wartości innej niż zero zostanie przekazany i wróci wcześniej, jeśli nie. Pozwala to nie martwić się tak bardzo o nieprawidłowe wskaźniki.

maniak zapadkowy
źródło
Pomyślałem o tym wzorze i uważam, że jest to absolutnie uzasadnione. Niestety nie wydaje się to tak jasne, jak assert(buffer);wiedząc, że assert jest aktywny tylko w przypadku wersji debugowania, czasami chcę mieć rt_assert(buffer);wyjątek. Wcięcie returnwygląda trochę niebezpiecznie ... BTW: fragment kodu jest dobrą ilustracją mojego pytania dotyczącego wskaźników wyjściowych.
Wolf
1

Wszystko sprowadza się do twoich obserwacji If an output parameter is required.

Jedynym miejscem, w którym sygnatura funkcji jest wymagana, aby mieć parametr wyjściowy, jest to, gdy jest ona określona przez zewnętrzny interfejs API, a w takim przypadku po prostu zawijasz zewnętrzny interfejs API w coś, co zapewnia, że ​​zawsze istnieje poprawna wskazówka.

Wewnętrznie unikasz parametrów wyjściowych, rozszerzając typ zwracany, aby był złożony ze wszystkich „outów”

Caleth
źródło
Masz na myśli, jedyne miejsce, w którym nie jestem w stanie podać nieobowiązkowego wskaźnika? To prawda, ale nie jestem pewien, czy twoja reguła The only place where...naprawdę ma zastosowanie do wszystkich przypadków. Jak sugerujesz wygląda: unikaj parametrów wyjściowych w funkcjach własnych programów. Prawda dla nowych programów.
Wolf
1
Tak, unikaj parametrów wyjściowych, preferuj złożone typy zwrotów, edytowane tak, aby były jaśniejsze
Caleth