Jak daleko posuniesz się const
? Czy po prostu wykonujesz funkcje, const
gdy jest to konieczne, czy chodzisz po całym świecie i używasz go wszędzie? Na przykład wyobraź sobie prostego mutatora, który przyjmuje pojedynczy parametr boolowski:
void SetValue(const bool b) { my_val_ = b; }
Czy to jest const
naprawdę przydatne? Osobiście wybieram go szeroko, łącznie z parametrami, ale w tym przypadku zastanawiam się, czy warto?
Byłem również zaskoczony, gdy dowiedziałem się, że można pominąć const
parametry w deklaracji funkcji, ale można to uwzględnić w definicji funkcji, np .:
plik .h
void func(int n, long l);
plik .cpp
void func(const int n, const long l)
Czy jest tego powód? Wydaje mi się to trochę niezwykłe.
Odpowiedzi:
Powodem jest to, że const dla parametru ma zastosowanie tylko lokalnie w obrębie funkcji, ponieważ działa ona na kopię danych. Oznacza to, że podpis funkcji jest w rzeczywistości taki sam. Jednak prawdopodobnie jest to zły styl.
Ja osobiście nie używam const z wyjątkiem parametrów odniesienia i wskaźnika. W przypadku skopiowanych obiektów nie ma to większego znaczenia, chociaż może być bezpieczniejszy, ponieważ sygnalizuje zamiary w obrębie funkcji. To naprawdę wyrok sądu. Zwykle jednak używam const_iterator podczas zapętlania czegoś i nie mam zamiaru go modyfikować, więc myślę, że każdy z nich ma własny, o ile rygorystycznie zachowana jest poprawność const dla typów referencyjnych.
źródło
const
z prototypów funkcji ma tę zaletę, że nie trzeba zmieniać pliku nagłówka, jeśli zdecydujesz sięconst
później zrezygnować z części implementacyjnej.const
tam, gdzie robi to użyteczną różnicę”.const
zawsze zaznaczam parametry ; jest bardziej ekspresyjny. Kiedy czytam kod innej osoby, używam takich małych wskaźników, aby ocenić, jak wiele uwagi poświęcają na pisanie kodu wraz z takimi rzeczami, jak magiczne liczby, komentowanie i właściwe używanie wskaźnika, itp.int getDouble(int a){ ++a; return 2*a; }
Spróbuj tego. Oczywiście++a
nie ma tam nic do roboty, ale można ją znaleźć w długiej funkcji napisanej przez więcej niż jednego programistę przez długi czas. Zdecydowanie sugerowałbym napisanieint getDouble( const int a ){ //... }
, które wygeneruje błąd kompilacji podczas wyszukiwania++a;
.class Foo { int multiply(int a, int b) const; }
w nagłówku. W swojej implementacji zależy ci na tym, abyś obiecał, że nie zmienisz,a
ib
dlategoint Foo::multiply(const int a, const int b) const { }
ma to sens. (Sidenote: zarówno program wywołujący, jak i implementacja dbają o to, aby funkcja nie zmieniała swojegoFoo
obiektu, a więc const na końcu deklaracji)„const nie ma sensu, gdy argument jest przekazywany przez wartość, ponieważ nie będziesz modyfikował obiektu obiektu wywołującego”.
Źle.
Chodzi o samodzielne udokumentowanie kodu i założeń.
Jeśli w twoim kodzie pracuje wiele osób, a twoje funkcje nie są trywialne, powinieneś zaznaczyć „const” dowolne i wszystko, co możesz. Pisząc kod przemysłowy, zawsze powinieneś zakładać, że twoi współpracownicy są psychopatami, próbującymi cię zdobyć w każdy możliwy sposób (zwłaszcza, że często w przyszłości jesteś sobą).
Poza tym, jak ktoś wcześniej wspomniał, może to pomóc kompilatorowi nieco zoptymalizować rzeczy (choć jest to długa szansa).
źródło
Czasami (zbyt często!) Muszę rozwikłać kod C ++ innej osoby. I wszyscy wiemy, że kod C ++ innej osoby jest z definicji kompletnym bałaganem :) Więc pierwszą rzeczą, którą robię, aby odszyfrować lokalny przepływ danych, jest const w każdej definicji zmiennej, dopóki kompilator nie zacznie szczekać. Oznacza to również argumenty wartości kwalifikującej const, ponieważ są to tylko fantazyjne zmienne lokalne zainicjowane przez program wywołujący.
Ach, chciałbym, żeby zmienne były domyślnie const i zmienne były wymagane dla zmiennych non-const :)
źródło
[x](){return ++x;}
jest błędem; patrz tutajconst
domyślnie „ ” w Rust :)Poniższe dwa wiersze są funkcjonalnie równoważne:
Oczywiście nie będziesz mógł modyfikować
a
w cielefoo
jeśli jest zdefiniowane w drugi sposób, ale nie ma różnicy z zewnątrz.Gdzie
const
naprawdę jest przydatna jest w parametrach referencyjnych lub palików:To oznacza, że foo może przyjąć duży parametr, być może strukturę danych o wielkości gigabajtów, bez kopiowania. Mówi także dzwoniącemu: „Foo * nie zmieni zawartości tego parametru”. Przekazanie stałego odwołania pozwala również kompilatorowi na podejmowanie określonych decyzji dotyczących wydajności.
*: Chyba że odrzuca ciągłość, ale to kolejny post.
źródło
Dodatkowe zbędne stałe są złe z punktu widzenia API:
Umieszczenie w kodzie dodatkowych zbędnych stałych dla parametrów typu wewnętrznego przekazywanych przez wartość zaśmieca interfejs API , nie dając żadnej znaczącej obietnicy użytkownikowi wywołującemu lub użytkownikowi interfejsu API (utrudnia to tylko implementację).
Zbyt wiele „stałych” w interfejsie API, gdy nie są potrzebne, jest jak „ płaczący wilk” ”, w końcu ludzie zaczną ignorować „stały”, ponieważ jest wszędzie i nic nie znaczy przez większość czasu.
Argument „reductio ad absurdum” do dodatkowych stałych w API jest dobry dla tych dwóch pierwszych punktów byłoby, gdyby więcej parametrów stałych było dobrych, to każdy argument, który może mieć na nim stałą, POWINIEN mieć na sobie stałą. W rzeczywistości, gdyby naprawdę był tak dobry, chciałbyś, aby const był domyślnym parametrem i miał słowo kluczowe takie jak „mutable” tylko wtedy, gdy chcesz zmienić parametr.
Spróbujmy więc wprowadzić const gdziekolwiek możemy:
Rozważ wiersz kodu powyżej. Deklaracja jest nie tylko bardziej zaśmiecona, dłuższa i trudniejsza do odczytania, ale trzy z czterech „stałych” słów kluczowych może bezpiecznie zignorować użytkownik interfejsu API. Jednak dodatkowe użycie „const” sprawiło, że druga linia potencjalnie NIEBEZPIECZNA!
Dlaczego?
Szybkie błędne odczytanie pierwszego parametru
char * const buffer
może sprawić, że pomyślisz, że nie zmodyfikuje on pamięci w przekazywanym buforze danych - nie jest to jednak prawda! Zbędne „stałe” mogą prowadzić do niebezpiecznych i niepoprawnych założeń dotyczących interfejsu API podczas szybkiego skanowania lub błędnego odczytu.Zbędne const są również złe z punktu widzenia implementacji kodu:
Jeśli FLEXIBLE_IMPLEMENTATION nie jest prawdą, to interfejs API „obiecuje”, że nie zaimplementuje funkcji w pierwszy sposób poniżej.
To bardzo głupia obietnica. Dlaczego należy składać obietnicę, która w ogóle nie przyniesie korzyści dzwoniącemu, a jedynie ograniczy wdrożenie?
Oba są doskonale poprawnymi implementacjami tej samej funkcji, więc niepotrzebnie przywiązujesz jedną rękę do pleców.
Co więcej, jest to bardzo płytka obietnica, którą łatwo (i legalnie obchodzi).
Słuchaj, zaimplementowałem go w ten sposób, mimo że obiecałem, że tego nie zrobię - tylko używając funkcji otoki. To tak, jakby złoczyńca obiecał, że nie zabije kogoś w filmie, i zamiast tego poleci swojemu poplecznikowi.
Te zbędne const są warte nie więcej niż obietnica złego filmowca.
Ale zdolność do kłamstwa staje się jeszcze gorsza:
Zostałem oświecony, że można niedopasować const w nagłówku (deklaracji) i kodzie (definicji) za pomocą fałszywego const. Zwolennicy const-happy twierdzą, że jest to dobra rzecz, ponieważ pozwala ona umieszczać const tylko w definicji.
Jednak odwrotność jest prawdziwa ... możesz umieścić fałszywą stałą tylko w deklaracji i zignorować ją w definicji. To sprawia, że zbędna stała w interfejsie API staje się bardziej okropną rzeczą i okropnym kłamstwem - zobacz ten przykład:
W rzeczywistości wszystko, co jest zbędne, powoduje, że kod implementatora jest mniej czytelny, zmuszając go do użycia innej lokalnej kopii lub funkcji opakowania, gdy chce zmienić zmienną lub przekazać zmienną przez odwołanie inne niż const.
Spójrz na ten przykład. Który jest bardziej czytelny? Czy jest oczywiste, że jedynym powodem dodatkowej zmiennej w drugiej funkcji jest to, że jakiś projektant API wrzucił zbędną stałą?
Mam nadzieję, że czegoś się tutaj nauczyliśmy. Zbędny const to zaśmiecony API, denerwujący nag, płytka i bezsensowna obietnica, niepotrzebna przeszkoda, a czasami prowadzi do bardzo niebezpiecznych błędów.
źródło
void foo(int)
ivoid foo(const int)
mają dokładnie tę samą funkcję, a nie przeciążenia. ideone.com/npN4W4 ideone.com/tZav9R Stała tutaj jest tylko szczegółem implementacji treści funkcji i nie ma wpływu na rozdzielczość przeciążenia. Pozostaw const z deklaracji, aby uzyskać bezpieczniejszy i bardziej czysty interfejs API, ale wstaw const do definicji , jeśli nie zamierzasz modyfikować skopiowanej wartości.pi++
wtedy, gdy nie powinni.stała powinna być domyślną w C ++. Lubię to :
źródło
unsigned
powinno być domyślnym w C ++. Jak to:int i = 5; // i is unsigned
isigned int i = 5; // i is signed
.Kiedy kodowałem C ++ do życia, stworzyłem wszystko, co mogłem. Korzystanie z const jest świetnym sposobem na pomoc kompilatorowi. Na przykład ograniczenie wartości zwracanych przez metodę może uchronić Cię przed literówkami, takimi jak:
kiedy miałeś na myśli:
Jeśli zdefiniowano foo (), aby zwracało odwołanie inne niż const:
Kompilator z przyjemnością pozwoli ci przypisać wartość do anonimowego tymczasowego zwróconego przez wywołanie funkcji. Robiąc to const:
Eliminuje tę możliwość.
źródło
foo() = 42
: błąd: wymagana wartość jako lewy argument przypisaniaconst int foo()
jest innego rodzaju niżint foo()
, co powoduje duże problemy, jeśli używasz takich wskaźników, jak wskaźniki funkcji, systemy sygnałów / gniazd lub boost :: bind.const int& foo()
efektywnie taki sam jakint foo()
ze względu na optymalizację wartości zwrotu?Dobra dyskusja na ten temat znajduje się w moderowanych tutaj starych artykułach „Guru tygodnia” na comp.lang.c ++ .
Odpowiedni artykuł GOTW jest dostępny na stronie internetowej Herb Sutter tutaj .
źródło
Mówię const swoje parametry wartości.
Rozważ tę funkcję buggy:
Jeśli parametr number byłby stały, kompilator zatrzymałby się i ostrzegłby nas o błędzie.
źródło
Używam const na parametrach funkcji, które są referencjami (lub wskaźnikami), które są tylko danymi wejściowymi i nie będą modyfikowane przez funkcję. Oznacza to, że celem użycia odwołania jest uniknięcie kopiowania danych i niedopuszczenie do zmiany przekazywanego parametru.
Nałożenie const na parametr boolean b w twoim przykładzie ogranicza tylko implementację i nie przyczynia się do interfejsu klasy (chociaż zwykle nie zaleca się zmiany parametrów).
Podpis funkcji dla
i
jest taki sam, co wyjaśnia twoje .c i .h
Asaf
źródło
Jeśli używasz operatorów
->*
lub.*
, jest to konieczne.To zapobiega pisaniu czegoś takiego
co prawie zrobiłem teraz i które prawdopodobnie nie robi tego, co zamierzacie.
Chciałem powiedzieć
i gdybym umieścić
const
pomiędzyBar *
ip
kompilator powiedziałby mi o tym.źródło
Ach, trudny. Z jednej strony deklaracja jest umową i naprawdę nie ma sensu przekazywać argumentu const według wartości. Z drugiej strony, jeśli spojrzysz na implementację funkcji, dajesz kompilatorowi większe możliwości optymalizacji, jeśli zadeklarujesz stałą argumentu.
źródło
const nie ma sensu, gdy argument jest przekazywany przez wartość, ponieważ nie będziesz modyfikował obiektu obiektu wywołującego.
const powinno być preferowane przy przekazywaniu przez referencję, chyba że celem funkcji jest modyfikacja przekazywanej wartości.
Wreszcie funkcja, która nie modyfikuje bieżącego obiektu (this), może i prawdopodobnie powinna zostać zadeklarowana jako const. Przykład jest poniżej:
Jest to obietnica niezmodyfikowania obiektu, do którego zastosowano to wywołanie. Innymi słowy, możesz zadzwonić:
Jeśli funkcja nie była stała, spowodowałoby to ostrzeżenie kompilatora.
źródło
Oznaczanie parametrów wartości „const” jest zdecydowanie rzeczą subiektywną.
Jednak tak naprawdę wolę oznaczać const parametry wartości, tak jak w twoim przykładzie.
Dla mnie wartość wyraźnie wskazuje, że wartości parametrów funkcji nigdy nie są zmieniane przez funkcję. Na początku będą miały tę samą wartość, co na końcu. Dla mnie jest to część utrzymywania bardzo funkcjonalnego stylu programowania.
W przypadku krótkiej funkcji jest zapewne stratą czasu / przestrzeni, aby mieć tam „const”, ponieważ zwykle dość oczywiste jest, że argumenty nie są modyfikowane przez funkcję.
Jednak w przypadku większej funkcji jest to forma dokumentacji implementacyjnej i jest egzekwowana przez kompilator.
Mogę być pewien, że jeśli wykonam jakieś obliczenia za pomocą „n” i „l”, mogę refaktoryzować / przenieść to obliczenie bez obawy o uzyskanie innego wyniku, ponieważ przegapiłem miejsce, w którym jedno lub oba zostały zmienione.
Ponieważ jest to szczegół implementacji, nie musisz deklarować const parametru wartości const w nagłówku, tak samo jak nie musisz deklarować parametrów funkcji o takich samych nazwach, jakich używa implementacja.
źródło
Może to nie będzie prawidłowy argument. ale jeśli zwiększymy wartość stałej zmiennej w kompilatorze funkcji, otrzymamy błąd: „ błąd: przyrost parametru tylko do odczytu ”. oznacza to, że możemy użyć słowa kluczowego const jako sposobu, aby zapobiec przypadkowej modyfikacji naszych zmiennych w funkcjach (których nie powinniśmy / tylko do odczytu). więc jeśli przypadkowo to zrobiliśmy podczas kompilacji, kompilator poinformuje nas o tym. jest to szczególnie ważne, jeśli nie jesteś jedynym, który pracuje nad tym projektem.
źródło
Kiedykolwiek to możliwe, używam const. (Lub inne odpowiednie słowo kluczowe dla języka docelowego.) Robię to wyłącznie dlatego, że pozwala to kompilatorowi na dokonanie dodatkowych optymalizacji, których inaczej nie byłby w stanie dokonać. Ponieważ nie mam pojęcia, czym mogą być te optymalizacje, zawsze robię to, nawet jeśli wydaje się to głupie.
Z tego, co wiem, kompilator może bardzo dobrze zobaczyć parametr stałej wartości i powiedzieć: „Hej, ta funkcja i tak go nie modyfikuje, więc mogę przejść przez odniesienie i zapisać kilka cykli zegara”. Nie sądzę, że kiedykolwiek zrobiłoby coś takiego, ponieważ zmienia podpis funkcji, ale ma sens. Może robi to różne manipulacje na stosie lub coś w tym rodzaju ... Chodzi o to, że nie wiem, ale wiem, że próba bycia mądrzejszym niż kompilator prowadzi tylko do wstydu.
C ++ ma dodatkowy bagaż z ideą stałej poprawności, więc staje się jeszcze ważniejszy.
źródło
const
. Raczej chodzi o ustalenie zamiaru w trakcie implementacji i późniejsze złapanie „cienkich” (przypadkowe zwiększenie niewłaściwej zmiennej lokalnej, ponieważ tak nie byłoconst
). Równolegle dodam również, że kompilatory są bardzo mile widziane do zmiany sygnatur funkcji, w tym sensie, że funkcje można wstawiać, a po wstawieniu można zmienić cały sposób ich działania; dodawanie lub usuwanie odniesień, tworzenie literałów „zmiennych” itp. mieszczą się w zasadzie „jak gdyby”1. Najlepsza odpowiedź na podstawie mojej oceny:
Odpowiedź @Adisak jest najlepszą odpowiedzią tutaj na podstawie mojej oceny. Zauważ, że ta odpowiedź jest częściowo najlepszy, ponieważ jest również najbardziej wycofał się z przykładami prawdziwy kod , oprócz korzystania dźwięk i dobrze przemyślanej logiki.
2. Moje własne słowa (zgadzając się z najlepszą odpowiedzią):
const
. Wszystko, co robi to:const
wszędzie może to utrudnić.const
niepotrzebnie zaśmieca kodconst
s wszędzie, odciągając uwagę od tych,const
które są naprawdę niezbędne do bezpiecznego kodu.const
jest niezwykle ważne w razie potrzeby i musi być stosowane, ponieważ zapobiega niepożądanym efektom ubocznym z utrzymującymi się zmianami poza funkcją, dlatego też każdy wskaźnik lub odniesienie musi być używane,const
gdy parm jest tylko danymi wejściowymi, nie wyjście. Używanieconst
tylko parametrów przekazywanych przez referencję lub wskaźnik ma dodatkową zaletę, ponieważ sprawia, że naprawdę oczywiste jest, które parametry są wskaźnikami lub referencjami. Jest jeszcze jedna rzecz, aby wystarczyć i powiedzieć „Uważaj! Dowolny paramconst
obok jest referencją lub wskaźnikiem!”.3. Słowa Google (zgadzając się ze mną i najlepsza odpowiedź):
(Z „ Przewodnika po stylu Google C ++ ”)
Źródło: sekcja „Korzystanie z const” Przewodnika po stylu Google C ++: https://google.github.io/styleguide/cppguide.html#Use_of_const . To jest naprawdę bardzo cenna sekcja, więc przeczytaj całą sekcję.
Zauważ, że „TotW # 109” oznacza „Wskazówka tygodnia nr 109: znacząca
const
w deklaracjach funkcji” , i jest również użyteczną lekturą. Jest bardziej informacyjny i mniej nakazowy co do tego, co zrobić, i na podstawie kontekstu pojawił się przed zasadą przewodnika po stylu Google C ++const
cytowaną tuż powyżej, ale ze względu na jej przejrzystość,const
zasada cytowana powyżej została dodana do Google C ++ Przewodnik po stylu.Zauważ też, że chociaż cytuję tutaj Przewodnik po stylu Google C ++ w obronie mojej pozycji, to wcale NIE oznacza, że zawsze postępuję zgodnie z tym przewodnikiem lub zawsze zalecam stosowanie się do niego. Niektóre rzeczy zalecają są po prostu dziwne, takie jak ich
kDaysInAWeek
-Style konwencji nazewnictwa dla „Constant Names” . Jednak nadal przydatne i istotne jest wskazanie, kiedy jedna z najbardziej udanych i wpływowych firm technicznych i programistycznych na świecie stosuje takie samo uzasadnienie, jak ja i inni, tacy jak @Adisak, aby poprzeć nasze poglądy na ten temat.4. Liner Clanga
clang-tidy
, ma kilka opcji:A. Warto również zauważyć, że linter dzyń, w
clang-tidy
, ma opcję,readability-avoid-const-params-in-decls
, opisane tutaj , aby wspierać egzekwowanie w bazie kodu nie używającconst
do parametrów funkcji pass-by-value :A oto dwa kolejne przykłady, które dodam siebie dla kompletności i jasności:
B. Ma również tę opcję:
readability-const-return-type
- https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html5. Moje pragmatyczne podejście do tego, jak sformułowałem przewodnik po stylu w tej sprawie:
Po prostu skopiuję i wkleję to do mojego przewodnika po stylach:
[KOPIUJ / WKLEJ START]
const
parametrów funkcji przekazywanych przez referencję lub wskaźnik, gdy ich zawartość (na co wskazują) NIE ma być zmieniana. W ten sposób staje się oczywiste, gdy zmienna przekazana przez referencję lub wskaźnik JEST oczekiwana do zmiany, ponieważ będzie jej brakowaćconst
. W tym przypadku użyciaconst
zapobiega przypadkowym skutkom ubocznym poza funkcją.const
parametrów funkcji przekazywanych przez wartość, ponieważconst
nie ma to wpływu na obiekt wywołujący: nawet jeśli zmienna zostanie zmieniona w funkcji, nie będzie żadnych efektów ubocznych poza funkcją. Zobacz następujące zasoby, aby uzyskać dodatkowe uzasadnienie i wgląd:const
deklaracje funkcji”const
[tj.const
Parametrów przekazywanych przez wartość ] do parametrów funkcji w deklaracjach, które nie są definicjami (i uważaj, aby nie kopiować / wklejać nic nie znaczącegoconst
). Jest to bez znaczenia i ignorowane przez kompilator, jest to szum wizualny , i może wprowadzać czytelników w błąd ”( https://abseil.io/tips/109 , podkreślenie dodane).const
kwalifikatorami mającymi wpływ na kompilację są te umieszczone w definicji funkcji, NIE te w deklaracji forward funkcji, takiej jak deklaracja funkcji (metody) w pliku nagłówkowym.const
[tj. Dlaconst
zmiennych przekazywanych przez wartość ] do wartości zwracanych przez funkcję.const
wskaźników lub referencji zwróconych przez funkcję zależy od implementatora , ponieważ czasami jest to przydatne.clang-tidy
opcjom:Oto kilka przykładów kodu pokazujących
const
reguły opisane powyżej:const
Przykłady parametrów:(niektóre są stąd zapożyczone )
const
Przykłady typu zwrotu:(niektóre są stąd zapożyczone )
[KOPIUJ / WKLEJ]
źródło
W przypadku, o którym wspominasz, nie wpływa to na osoby wywołujące interfejs API, dlatego nie jest to często wykonywane (i nie jest konieczne w nagłówku). Wpływa tylko na implementację twojej funkcji.
Nie jest to szczególnie zła rzecz do zrobienia, ale korzyści nie są tak świetne, biorąc pod uwagę, że nie wpływa to na interfejs API i dodaje pisanie, więc zwykle nie jest to zrobione.
źródło
Nie używam const dla parametru przekazywanego przez wartość. Dzwoniący nie dba o to, czy zmienisz parametr, czy nie, jest to szczegół implementacji.
Naprawdę ważne jest oznaczenie metod jako const, jeśli nie modyfikują one swojego wystąpienia. Rób to w miarę postępów, ponieważ w przeciwnym razie możesz skończyć z dużą ilością const_cast <> lub może się okazać, że oznaczenie metody const wymaga zmiany dużej ilości kodu, ponieważ wywołuje inne metody, które powinny być oznaczone const.
Zazwyczaj zaznaczam lokalne zmienne war, jeśli nie muszę ich modyfikować. Uważam, że ułatwia to zrozumienie kodu, ułatwiając identyfikację „ruchomych części”.
źródło
Optymalizacje kompilatora: http://www.gotw.ca/gotw/081.htm
źródło
Używam const, gdybym mógł. Stała dla parametrów oznacza, że nie powinny zmieniać swojej wartości. Jest to szczególnie cenne przy przekazywaniu przez odniesienie. const dla funkcji deklaruje, że funkcja nie powinna zmieniać członków klas.
źródło
Podsumowując:
std::vector::at(size_type pos)
. To, co wystarcza dla standardowej biblioteki, jest dla mnie dobre.źródło
_Tmp
cały czas - nie chcesz tego (w rzeczywistości nie możesz ich używać).Jeśli parametr jest przekazywany przez wartość (i nie jest referencją), zwykle nie ma dużej różnicy, czy parametr jest zadeklarowany jako const, czy nie (chyba że zawiera element referencyjny - nie jest to problem dla typów wbudowanych). Jeśli parametr jest odniesieniem lub wskaźnikiem, zwykle lepiej jest chronić pamięć odniesienia / wskazaną do pamięci, a nie sam wskaźnik (myślę, że nie możesz ustawić samego odniesienia, nie ma to znaczenia, ponieważ nie możesz zmienić sędziego) . Dobrym pomysłem jest ochrona wszystkiego, co możesz jako const. Możesz go pominąć bez obawy, że popełnisz błąd, jeśli parametry to tylko POD (w tym typy wbudowane) i nie ma szans na ich dalszą zmianę na drodze (np. W twoim przypadku parametr bool).
Nie wiedziałem o różnicy deklaracji pliku .h / .cpp, ale ma to jakiś sens. Na poziomie kodu maszynowego nic nie jest „const”, więc jeśli zadeklarujesz funkcję (w .h) jako non-const, kod będzie taki sam, jakbyś zadeklarował ją jako const (pomijając optymalizacje). Pomaga to jednak zapisać kompilatorowi, że nie zmienisz wartości zmiennej wewnątrz implementacji funkcji (.ccp). Może się to przydać w przypadku dziedziczenia po interfejsie, który umożliwia zmianę, ale nie trzeba zmieniać parametru, aby osiągnąć wymaganą funkcjonalność.
źródło
Nie nakładałbym const na takie parametry - wszyscy już wiedzą, że wartość logiczna (w przeciwieństwie do wartości logicznej i) jest stała, więc dodanie jej sprawi, że ludzie pomyślą „czekaj, co?” a nawet że przekazujesz parametr przez odniesienie.
źródło
rzeczą, o której należy pamiętać w const, jest to, że o wiele łatwiej jest tworzyć rzeczy const od samego początku, niż próbować włożyć je później.
Użyj const, jeśli chcesz, aby coś się nie zmieniło - to dodatkowa wskazówka, która opisuje, co robi twoja funkcja i czego się spodziewać. Widziałem wiele C API, które mogłyby zrobić z niektórymi z nich, szczególnie tymi, które akceptują ciągi c!
Byłbym bardziej skłonny do pominięcia słowa kluczowego const w pliku cpp niż w nagłówku, ale ponieważ mam tendencję do wycinania i wklejania ich, byłyby one przechowywane w obu miejscach. Nie mam pojęcia, dlaczego kompilator na to pozwala, wydaje mi się, że jest to kompilator. Najlepszą praktyką jest zdecydowanie umieszczenie słowa kluczowego const w obu plikach.
źródło
Naprawdę nie ma powodu, aby tworzyć parametr-wartość „const”, ponieważ funkcja może i tak modyfikować tylko kopię zmiennej.
Powodem użycia „const” jest podanie przez odniesienie czegoś większego (np. Struktury z dużą liczbą elementów), w którym to przypadku zapewnia, że funkcja nie może go zmodyfikować; a raczej kompilator narzeka, jeśli spróbujesz go zmodyfikować w tradycyjny sposób. Zapobiega to przypadkowej modyfikacji.
źródło
Stały parametr jest użyteczny tylko wtedy, gdy parametr jest przekazywany przez referencję, tj. Referencję lub wskaźnik. Gdy kompilator zobaczy parametr const, upewnij się, że zmienna użyta w parametrze nie jest modyfikowana w treści funkcji. Dlaczego ktoś miałby chcieć ustawić parametr wartości według wartości jako stały? :-)
źródło
const
jasno mówi: „Nie muszę tego zmieniać, więc to deklaruję. Jeśli spróbuję go później zmodyfikować, daj mi błąd czasu kompilacji, abym mógł naprawić swój błąd lub odznaczyć go jakoconst
”. To kwestia higieny i bezpieczeństwa kodu. Wszystko, czego potrzeba, aby dodać do plików implementacyjnych, powinno być czymś, co ludzie robią jako czysty refleks, IMO.Ponieważ parametry są przekazywane przez wartość, nie ma znaczenia, czy podasz const, czy nie z perspektywy funkcji wywołującej. Zasadniczo nie ma sensu deklarować parametrów pass by value jako const.
źródło
Wszystkie consts w twoich przykładach nie mają celu. C ++ jest domyślnie przekazywany przez wartość, więc funkcja pobiera kopie tych liczb całkowitych i logicznych. Nawet jeśli funkcja je zmodyfikuje, nie wpłynie to na kopię dzwoniącego.
Więc unikałbym dodatkowych stałych, ponieważ
źródło
Wiem, że pytanie jest „trochę” nieaktualne, ale kiedy do niego dotarłem, ktoś inny może to zrobić w przyszłości ... ... wciąż wątpię, żeby biedny człowiek tu listy, aby przeczytać mój komentarz :)
Wydaje mi się, że wciąż jesteśmy zbyt ograniczeni do myślenia w stylu C. W paradygmacie OOP bawimy się przedmiotami, a nie typami. Obiekt Const może być koncepcyjnie różny od obiektu non-const, szczególnie w sensie const logical (w przeciwieństwie do const logicznego). Zatem nawet jeśli stała poprawność parametrów funkcji jest (być może) nadmierną ostrożnością w przypadku POD, nie jest tak w przypadku obiektów. Jeśli funkcja działa z obiektem const, powinna to powiedzieć. Rozważ następujący fragment kodu
ps .: możesz argumentować, że odniesienie (const) byłoby bardziej odpowiednie tutaj i daje ci to samo zachowanie. Racja. Daję inny obraz niż to, co widziałem gdzie indziej ...
źródło