Użycie "const" dla parametrów funkcji

Jak daleko zajdziesz z const? Czy po prostu tworzysz funkcje const, gdy jest to konieczne, czy chodzisz cały czas i używasz go wszędzie? Na przykład, wyobraź sobie prosty mutator, który przyjmuje pojedynczy parametr logiczny:

void SetValue(const bool b) { my_val_ = b; }
Czy to jest użyteczne? Osobiście zdecyduję się na jego szerokie wykorzystanie, w tym parametry, ale w tym przypadku zastanawiam się, czy warto?

Byłem również zaskoczony, że można pominąć const z parametrów w deklaracji funkcji ale może zawierać ją w definicji funkcji, np.:

.plik h

void func(int n, long l);

.plik cpp

void func(const int n, const long l)
Czy jest ku temu jakiś powód? Wydaje mi się to trochę niezwykłe.
 433
Author: Michael Myers, 2008-09-22

30 answers

Powodem jest to, że const dla parametru stosuje się tylko lokalnie w ramach funkcji, ponieważ działa on na kopii danych. Oznacza to, że podpis funkcji jest tak naprawdę taki sam. To prawdopodobnie zły styl, aby to robić często.

Osobiście zazwyczaj nie używam const z wyjątkiem parametrów odniesienia i wskaźnika. W przypadku kopiowanych obiektów nie ma to znaczenia, chociaż może być bezpieczniejsze, ponieważ sygnalizuje intencję w funkcji. To naprawdę decyzja sądu. Zwykle używam const_iterator choć przy zapętlaniu czegoś i nie zamierzam tego modyfikować, więc myślę, że każdy ma swój własny, o ile const poprawność dla typów odniesienia jest rygorystycznie utrzymywana.

 197
Author: Greg Rogers,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-24 13:41:47

const jest bez sensu, gdy argument jest przekazywany przez wartość, ponieważ będziesz nie modyfikować obiektu wywołującego.

Źle. Chodzi o samodzielne dokumentowanie kodu i założeń.

Jeśli Twój kod ma wiele osób pracujących nad nim i twoje funkcje są nietrywialne, powinieneś zaznaczyć const wszystko, co możesz. Pisząc przemysłowy kod, zawsze powinieneś zakładać, że Twoi współpracownicy to psychopaci, którzy próbują cię w jakikolwiek sposób mogą (zwłaszcza, że to często ty w przyszłości).

Poza tym, jak ktoś wcześniej wspomniał, to Może pomóc kompilatorowi nieco zoptymalizować rzeczy (choć to długi strzał).

 441
Author: rlerallut,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-11-24 13:39:30

Sometimes (zbyt często!) Muszę rozplątać cudzy kod C++. I wszyscy wiemy, że czyjś Kod c++ jest kompletnym bałaganem prawie z definicji :) więc pierwszą rzeczą, jaką robię, aby rozszyfrować lokalny przepływ danych, jest umieszczenie const w każdej definicji zmiennej, dopóki kompilator nie zacznie szczekać. Oznacza to również argumenty const-qualifying value, ponieważ są to tylko wymyślne zmienne lokalne inicjowane przez wywołującego.

Ah, szkoda, że zmienne nie były const domyślnie i mutable było wymagane dla zmiennych niekonst:)

 163
Author: Constantin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-06-17 08:56:04

Następujące dwie linie są funkcjonalnie równoważne:

int foo (int a);
int foo (const int a);

Oczywiście nie będziesz w stanie modyfikować a w ciele foo jeśli jest zdefiniowany w drugi sposób, ale nie ma różnicy od zewnątrz.

Gdzie const naprawdę przydaje się z parametrami odniesienia lub wskaźnika:

int foo (const BigStruct &a);
int foo (const BigStruct *a);

Mówi to, że foo może pobierać duży parametr, być może strukturę danych o rozmiarze gigabajtów, bez kopiowania go. Ponadto mówi do rozmówcy: "Foo nie zmieni się zawartość tego parametru."Przekazanie referencji const pozwala również kompilatorowi na podejmowanie określonych decyzji dotyczących wydajności.

*: chyba, że odrzuci to const-ness, ale to kolejny post.

 84
Author: Ben Straub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:36:58

Extra zbędne const są złe z punktu bazowego API:

Umieszczenie dodatkowych zbędnych const w kodzie dla wewnętrznych parametrów typu przekazywanych przez wartość zaśmieca API, nie składając przy tym żadnej znaczącej obietnicy dla wywołującego lub użytkownika API (utrudnia jedynie implementację).

Zbyt wiele 'const' w API, gdy nie jest potrzebne, jest jak " płaczący Wilk", W końcu ludzie zaczną ignorować 'const', ponieważ jest wszędzie i nic nie znaczy większość czas.

Argument "reductio ad absurdum" do dodatkowych const w API jest dobry dla tych dwóch pierwszych punktów, jeśli więcej parametrów const jest dobrych, to każdy argument, który może mieć const na nim, powinien mieć const na nim. W rzeczywistości, gdyby był naprawdę tak dobry, chciałbyś, aby const był domyślnym parametrem i miał słowo kluczowe takie jak" mutable " tylko wtedy, gdy chcesz zmienić parametr.

Więc spróbujmy umieścić w const gdzie tylko możemy:

void mungerum(char * buffer, const char * mask, int count);

void mungerum(char * const buffer, const char * const mask, const int count);

Rozważmy linię kodu powyżej. Nie tylko deklaracja jest bardziej zaśmiecona, dłuższa i trudniejsza do odczytania, ale trzy z czterech słów kluczowych "const" mogą być bezpiecznie ignorowane przez użytkownika API. Jednak dodatkowe użycie "const" uczyniło drugą linię potencjalnie niebezpieczną!

Dlaczego?

Szybkie błędne odczytanie pierwszego parametru char * const buffer może sprawić, że pomyślisz, że nie zmodyfikuje on pamięci w buforze danych, który jest przekazywany - jednak nie jest to prawdą! zbędne "const" może prowadzić do niebezpiecznego i błędne założenia dotyczące API podczas szybkiego skanowania lub błędnego odczytu.


Zbędne const są również złe z punktu postoju implementacji kodu:

#if FLEXIBLE_IMPLEMENTATION
       #define SUPERFLUOUS_CONST
#else
       #define SUPERFLUOUS_CONST             const
#endif

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count);

Jeśli FLEXIBLE_IMPLEMENTATION nie jest prawdą, to API "obiecuje", że nie zaimplementuje funkcji w pierwszy sposób poniżej.

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       // Will break if !FLEXIBLE_IMPLEMENTATION
       while(count--)
       {
              *dest++=*source++;
       }
}

void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source, SUPERFLUOUS_CONST int count)
{
       for(int i=0;i<count;i++)
       {
              dest[i]=source[i];
       }
}
To bardzo głupia obietnica. Dlaczego warto złożyć obietnicę, która nie przynosi żadnych korzyści rozmówcy i ogranicza tylko realizację?

Oba są doskonale poprawne implementacje tej samej funkcji, więc wszystko, co zrobiłeś, to niepotrzebnie związana jedna ręka za plecami.

Co więcej, jest to bardzo płytka obietnica, która jest łatwo (i prawnie obchodzona).
inline void bytecopyWrapped(char * dest,
   const char *source, int count)
{
       while(count--)
       {
              *dest++=*source++;
       }
}
void bytecopy(char * SUPERFLUOUS_CONST dest,
   const char *source,SUPERFLUOUS_CONST int count)
{
    bytecopyWrapped(dest, source, count);
}

Spójrz, i tak zaimplementowałem to w ten sposób, mimo że obiecałem tego nie robić – po prostu używając funkcji wrappera. To tak, jak wtedy, gdy zły facet obiecuje, że nie zabije kogoś w filmie i każe swojemu poplecznikowi go zabić.

Te zbędne const są nie wart więcej niż obietnica z filmu złoczyńca.


Ale umiejętność kłamania staje się jeszcze gorsza:

Zostałem oświecony, że można niezgodnie z const w nagłówku (deklaracji) i kodzie (definicji) za pomocą fałszywych const. Zwolennicy const-happy twierdzą, że jest to dobra rzecz, ponieważ pozwala umieścić const tylko w definicji.

// Example of const only in definition, not declaration
struct foo { void test(int *pi); };
void foo::test(int * const pi) { }

Jednak konwersacja jest prawdziwa... możesz umieścić fałszywy const tylko w deklaracji i zignorować go w definicji. To tylko sprawia, że zbędne const w API bardziej straszne rzeczy i straszne kłamstwo-zobacz ten przykład:

struct foo
{
    void test(int * const pi);
};

void foo::test(int *pi) // Look, the const in the definition is so superfluous I can ignore it here
{
    pi++;  // I promised in my definition I wouldn't modify this
}

Wszystko, co zbędne const faktycznie robi, to sprawia, że kod wykonawcy jest mniej czytelny, zmuszając go do użycia innej lokalnej kopii lub funkcji wrappera, gdy chce zmienić zmienną lub przekazać zmienną przez odniesienie non-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ędny const ?

struct llist
{
    llist * next;
};

void walkllist(llist *plist)
{
    llist *pnext;
    while(plist)
    {
        pnext=plist->next;
        walk(plist);
        plist=pnext;    // This line wouldn't compile if plist was const
    }
}

void walkllist(llist * SUPERFLUOUS_CONST plist)
{
    llist * pnotconst=plist;
    llist *pnext;
    while(pnotconst)
    {
        pnext=pnotconst->next;
        walk(pnotconst);
        pnotconst=pnext;
    }
}

Mam nadzieję, że czegoś się tu nauczyliśmy. Zbędne const jest API-zaśmiecanie oczu, irytujące zrzędzenie, płytka i bezsensowna obietnica, niepotrzebna przeszkoda, a czasami prowadzi do bardzo niebezpiecznych błędów.
 78
Author: Adisak,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-12-10 18:48:51

Const powinien być domyślnym w C++. Tak:

int i = 5 ; // i is a constant

var int i = 5 ; // i is a real variable
 39
Author: QBziZ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 11:43:18

Kiedy zarabiałem na życie kodowaniem C++, robiłem wszystko, co mogłem. Korzystanie z const jest świetnym sposobem, aby pomóc kompilator pomóc ci. Na przykład, const-ing wartości zwracane przez metodę mogą uchronić Cię przed literówkami, takimi jak:

foo() = 42

Kiedy miałeś na myśli:

foo() == 42

Jeśli foo () jest zdefiniowane w celu zwrócenia odwołania non-const:

int& foo() { /* ... */ }

Kompilator z radością pozwoli Ci przypisać wartość do anonimowego tymczasowego zwracanego przez wywołanie funkcji. Robi to const:

const int& foo() { /* ... */ }

Eliminuje taka możliwość.

 24
Author: Avdi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-11-28 20:05:01

Jest dobra dyskusja na ten temat w starych artykułach" Guru tygodnia " na comp.lang.c++.moderowane tutaj .

Odpowiedni artykuł GOTW jest dostępny na stronie Herb Sutter tutaj .

 15
Author: Void,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 22:37:28

Mówię const swoje parametry wartości.

Rozważmy tę funkcję:

bool isZero(int number)
{
  if (number = 0)  // whoops, should be number == 0
    return true;
  else
    return false;
}

Gdyby parametr number był const, kompilator zatrzymałby się i ostrzegłby nas o błędzie.

 9
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-11-14 13:38:17

Używam const na parametrach funkcji, które są referencjami (lub wskaźnikami), które są tylko [w] danych i nie będą modyfikowane przez funkcję. Znaczenie, gdy celem użycia referencji jest uniknięcie kopiowania danych i nie umożliwienie zmiany przekazanego parametru.

Umieszczenie const na parametrze boolean b w twoim przykładzie tylko ogranicza implementację i nie przyczynia się do interfejsu klasy (chociaż zwykle zaleca się nie zmienianie parametrów).

The podpis funkcji dla

void foo(int a);

I

void foo(const int a);

To to samo, co wyjaśnia Twoje .c i .h

Asaf

 8
Author: Asaf R,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:23:56

Jeśli używasz operatorów ->* lub .*, jest to konieczne.

Uniemożliwia pisanie czegoś takiego

void foo(Bar *p) { if (++p->*member > 0) { ... } }
Co prawie teraz zrobiłem, i prawdopodobnie nie robi tego, co zamierzacie.

To co chciałem powiedzieć to

void foo(Bar *p) { if (++(p->*member) > 0) { ... } }

I gdybym umieścił const pomiędzy Bar * a p, kompilator by mi to powiedział.

 6
Author: user541686,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-06-20 09:12:55

1. Najlepsza odpowiedź na podstawie mojej oceny:

Odpowiedź @Adisak jest najlepszą odpowiedzią tutaj na podstawie mojej oceny. Zauważ, że ta odpowiedź jest po części najlepsza, ponieważ jest również najbardziej dobrze popartą prawdziwymi przykładami kodu, oprócz korzystania z dźwięku i przemyślanej logiki.

2. Moje własne słowa (zgadzając się z najlepszą odpowiedzią):

  1. Dla wartości pass-by-value nie ma korzyści z dodania const. All it does na:
    1. ogranicz wykonawcę, aby musiał wykonać kopię za każdym razem, gdy chce zmienić param wejściowy w kodzie źródłowym (co i tak nie miałoby skutków ubocznych, ponieważ to, co zostało przekazane, jest już kopią, ponieważ jest wartością pass-by-value). Często do implementacji funkcji używa się zmiennej wejściowej, która jest przekazywana przez wartość, więc dodanie const wszędzie może to utrudnić.
    2. i dodanie const niepotrzebnie zaśmieca kod const wszędzie, przyciągając uwagę z const S, które są naprawdę niezbędne, aby mieć bezpieczny kod.
  2. gdy mamy do czynienia z wskaźnikami lub referencjami, jednak const jest krytycznie ważne, gdy jest to konieczne, i musi być używany, ponieważ zapobiega niepożądanym efektom ubocznym z trwałymi zmianami poza funkcja, a zatem każdy pojedynczy wskaźnik lub odniesienie musi używaćconst, gdy jest tylko wejściem, nie wyjściem. Za pomocą const tylko na parametrach przekazywany przez odniesienie lub wskaźnik ma dodatkową zaletę, czyniąc naprawdę oczywistym , które parametry są wskaźnikami lub odniesieniami. To jeszcze jedna rzecz, aby wystylizować się i powiedzieć " uważaj! Każdy param z const obok jest referencją lub Wskaźnikiem!".
  3. to, co opisałem powyżej, często było konsensusem osiągniętym w profesjonalnych organizacjach programistycznych, w których pracowałem, i zostało uznane za najlepszą praktykę. Czasami nawet zasada była ścisła: "nigdy nie używaj const na parametrach, które są przekazywane przez wartość, ale zawsze używać go na parametrach przekazywanych przez odniesienie lub wskaźnik, jeżeli są tylko wejściami."

3. słowa Google (zgadzam się ze mną i najlepsza odpowiedź):

(Z "Google C++ Style Guide")

Dla parametru funkcji przekazanego przez wartość, const nie ma wpływu na wywołujący, dlatego nie jest zalecany w deklaracjach funkcji. Zobacz TotW #109.

Używanie const na zmiennych lokalnych nie jest ani zachęcany, ani zniechęcany.

Źródło: sekcja "Use of const" w Google C++ Style Guide: https://google.github.io/styleguide/cppguide.html#Use_of_const . jest to naprawdę bardzo cenna sekcja, więc przeczytaj całą sekcję.

Zauważ, że "TotW #109" oznacza "Tip of the Week #109: meaning const in Function Declarations" i jest również przydatną lekturą. Jest bardziej pouczające i mniej nakazowe, co do do, i na podstawie kontekstu przyszedł przed reguła Google C++ Style Guide na const cytowany tuż powyżej, ale w wyniku przejrzystości, to zapewniło, const reguła cytowany tuż powyżej został dodany do Google C++ Style Guide.

Zauważ również, że chociaż cytuję tutaj Przewodnik po stylu Google C++ w obronie mojego stanowiska, nie oznacza to, że zawsze podążam za przewodnikiem lub zawsze polecam podążanie za przewodnikiem. Niektóre z rzeczy, które polecają, są po prostu dziwne, takie jak ich kDaysInAWeek-stylowa konwencja nazewnictwa dla "Stałych nazw". niemniej jednak, jest to nadal przydatne i istotne, aby wskazać, kiedy jedna z najbardziej udanych i wpływowych firm technicznych i programistycznych na świecie używa tego samego uzasadnienia, co ja I inni, tacy jak @Adisak, aby potwierdzić nasze poglądy w tej sprawie.

4. Clang ' s linter, clang-tidy, ma kilka opcji do tego:

A. Warto również zauważyć, że linter clanga, clang-tidy, ma opcję, readability-avoid-const-params-in-decls, opisane tutaj , aby wspierać egzekwowanie w bazie kodu , a nie używanie const dla parametrów funkcji pass-by-value :

Sprawdza, czy deklaracja funkcji ma parametry, które są najwyższym poziomem const.

Wartości Const w deklaracjach nie wpływają na sygnaturę funkcji, więc nie powinny być tam umieszczane.

Przykłady:

void f(const string);   // Bad: const is top level.
void f(const string&);  // Good: const is not top level.

A oto jeszcze dwa przykłady, które dodaję dla kompletności i jasność:

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

B. ma również tę opcję: readability-const-return-type - https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

5. Moje pragmatyczne podejście do tego, jak powiedziałbym przewodnik stylu w tej sprawie: {]}

Po prostu skopiowałbym i wkleił to do mojego przewodnika po stylach:

[KOPIUJ/WKLEJ POCZĄTEK]

  1. Zawsze używaj const na parametrach funkcji przekazywanych przez referencję lub wskaźnik, gdy ich zawartość (na co wskazują) jest przeznaczona Nie do zmiany. W ten sposób staje się oczywiste, gdy zmienna przekazywana przez odniesienie lub wskaźnik ma zostać zmieniona, ponieważ nie będzie jej brakowało const. W tym przypadku const zapobiega przypadkowym skutkom ubocznym poza funkcją.
  2. jest nie zaleca się używania const na parametrach funkcji przekazywanych przez wartość, ponieważ const nie ma wpływu na 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 dla dodatkowego uzasadnienia i wglądu:
    1. "Google C++ Style Guide" "Use of const" section
    2. "Tip of the Week #109: meaning const in Function Declarations"
    3. odpowiedź Adisaka na "użycie' const 'dla parametrów funkcji"
  3. "nigdy nie używaj najwyższego poziomu const [ie: const na parametrach przekazywanych przez wartość ] na parametrach funkcji w deklaracjach , które nie są definicje (i uważaj, aby nie skopiować / wkleić bezsensownego const). Jest on bezsensowny i ignorowany przez kompilator, jest wizualnym szumem i może wprowadzać czytelników w błąd "([91]}https://abseil.io/tips/109 , podkreślenie dodane).
    1. jedynymi kwalifikatorami const, które mają wpływ na kompilację, są te umieszczone w definicji funkcji, a nie w deklaracji forward funkcji, np. w deklaracji funkcji (metody) w pliku nagłówkowym.
  4. nigdy nie używaj najwyższego poziomu const [ie: constna zmiennych przekazywanych przez wartość ] na wartościach zwracanych przez funkcję.
  5. użycie const na wskaźnikach lub referencjach zwracanych przez funkcję jest aż do implementatora , ponieważ czasami jest to przydatne.
  6. TODO: wymusić niektóre z powyższych za pomocą następujących clang-tidy opcje:
    1. https://clang.llvm.org/extra/clang-tidy/checks/readability-avoid-const-params-in-decls.html
    2. https://clang.llvm.org/extra/clang-tidy/checks/readability-const-return-type.html

Oto kilka przykładów kodu, aby zademonstrować const zasady opisane powyżej:

const Przykłady Parametrów:
(niektóre są zapożyczone z tutaj )

void f(const std::string);   // Bad: const is top level.
void f(const std::string&);  // Good: const is not top level.

void f(char * const c_string);   // Bad: const is top level. [This makes the _pointer itself_, NOT what it points to, const]
void f(const char * c_string);   // Good: const is not top level. [This makes what is being _pointed to_ const]

const Typ Zwrotu Przykłady:
(niektóre są zapożyczone z tutaj )

// BAD--do not do this:
const int foo();
const Clazz foo();
Clazz *const foo();

// OK--up to the implementer:
const int* foo();
const int& foo();
const Clazz* foo();

[KONIEC KOPIOWANIA/WKLEJANIA]

 6
Author: Gabriel Staples,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2020-04-26 06:26:59

Ach, trudne. Z jednej strony deklaracja jest umową i naprawdę nie ma sensu przekazywać argumentu const przez wartość. Z drugiej strony, jeśli spojrzysz na implementację funkcji, dasz kompilatorowi większe szanse na optymalizację, jeśli zadeklarujesz stałą argumentu.

 5
Author: Nemanja Trifunovic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:18:31

Const jest bezcelowe, gdy argument jest przekazywany przez wartość, ponieważ nie będziesz modyfikować obiektu wywołującego.

Const powinien być preferowany 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 być zadeklarowana const. Przykład znajduje się poniżej:

int SomeClass::GetValue() const {return m_internalValue;}

Jest to obietnica nie modyfikowania obiektu, do którego to wywołanie jest stosowane. Innymi słowy, ty można wywołać:

const SomeClass* pSomeClass;
pSomeClass->GetValue();

Gdyby funkcja nie była const, spowodowałoby to Ostrzeżenie kompilatora.

 5
Author: Dan Hewett,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:40:11

Oznaczanie parametrów wartości 'const' jest zdecydowanie rzeczą subiektywną.

Jednak wolę oznaczyć parametry wartości const, tak jak w twoim przykładzie.

void func(const int n, const long l) { /* ... */ }

Wartość dla mnie jest wyraźnie wskazująca, że wartości parametrów funkcji nigdy nie są zmieniane przez funkcję. Będą miały taką samą wartość na początku, jak na końcu. Dla mnie jest to część trzymania się bardzo funkcjonalnego stylu programowania.

Dla krótkiej funkcji jest to prawdopodobnie marnotrawstwo czas / przestrzeń, aby mieć tam 'const', ponieważ zwykle jest dość oczywiste, że argumenty nie są modyfikowane przez funkcję.

Jednak dla większej funkcji, jest to forma dokumentacji implementacji i jest egzekwowana przez kompilator.

Mogę być pewien, że jeśli wykonam jakieś obliczenia za pomocą " n " I "l", mogę refaktorować / przenieść te obliczenia bez obawy o uzyskanie innego wyniku, ponieważ przegapiłem miejsce, w którym jedna lub obie są zmienione.

Ponieważ jest to implementacja detail, nie musisz deklarować parametrów wartości const w nagłówku, tak jak nie musisz deklarować parametrów funkcji o takich samych nazwach, jakich używa implementacja.

 5
Author: Lloyd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 22:58:07

Może to nie być prawidłowy argument. ale jeśli zwiększymy wartość zmiennej const wewnątrz kompilatora funkcji da nam błąd: "error: increment of read-only parameter ". oznacza to, że możemy użyć słowa kluczowego const jako sposobu, aby zapobiec przypadkowej modyfikacji naszych zmiennych wewnątrz funkcji(których nie powinniśmy / tylko do odczytu). jeśli więc przypadkowo zrobiliśmy to w czasie kompilacji, kompilator da nam o tym znać. jest to szczególnie ważne, jeśli nie jesteś jedynym, który jest pracuję nad tym projektem.

 4
Author: HarshaXsoad,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-03 21:21:34

Używam const wszędzie, gdzie to możliwe. (Lub inne odpowiednie słowo kluczowe dla języka docelowego.) Robię to wyłącznie dlatego, że pozwala kompilatorowi na dodatkowe optymalizacje, których nie byłby w stanie zrobić w przeciwnym razie. Ponieważ nie mam pojęcia, jakie mogą być te optymalizacje, zawsze to robię, nawet tam, gdzie wydaje się to głupie.

Z tego co wiem, kompilator może bardzo dobrze zobaczyć parametr const value i powiedzieć: "Hej, ta funkcja i tak go nie modyfikuje, więc mogę przejść przez referencję i zapisać kilka cykli zegarowych."Nie sądzę, że kiedykolwiek zrobiłby coś takiego, ponieważ zmienia podpis funkcji, ale to ma sens. Może to jakaś inna manipulacja stosem czy coś... Chodzi o to, że nie wiem, ale wiem, że próba bycia mądrzejszym od kompilatora prowadzi tylko do wstydu.

C++ ma jakiś dodatkowy bagaż, z ideą const-poprawności, więc staje się jeszcze ważniejszy.

 3
Author: jdmichal,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:36:13

W przypadku, gdy wspomniałeś, nie wpływa to na wywołujących twojego API, dlatego nie jest to często wykonywane(i nie jest konieczne w nagłówku). Wpływa tylko na realizację funkcji.

Nie jest to szczególnie złe, ale korzyści nie są tak wielkie, biorąc pod uwagę, że nie wpływa to na API, i dodaje wpisywanie, więc zwykle nie jest zrobione.

 2
Author: Luke Halliwell,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:17:14

Nie używam const do parametru przekazanego przez wartość. Wywołujący nie dba o to, czy zmodyfikujesz parametr, czy nie, jest to szczegół implementacji.

To, co jest naprawdę ważne, to oznaczanie metod jako const, jeśli nie modyfikują One swojej instancji. Rób to jak chcesz, ponieważ w przeciwnym razie możesz skończyć z dużą ilością const_cast lub może się okazać, że oznaczanie metody const wymaga zmiany dużej ilości kodu, ponieważ wywołuje inne metody, które powinny być oznaczone const.

Mam też tendencję do oznaczania lokalnych VAR-ów const, jeśli nie muszę ich modyfikować. Wierzę, że ułatwia to zrozumienie kodu, ułatwiając identyfikację "ruchomych części".

 2
Author: Aurélien Gâteau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:24:43

Na temat optymalizacji kompilatora: http://www.gotw.ca/gotw/081.htm

 2
Author: sdcvvc,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-05 21:53:39

Używam const w miarę możliwości. Const dla parametrów oznacza, że nie powinny one zmieniać swojej wartości. Jest to szczególnie cenne podczas przechodzenia przez odniesienie. const for function deklaruje, że funkcja nie powinna zmieniać członków klas.

 2
Author: Dror Helper,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-03-28 16:02:44

Podsumowując:

  • "Zwykle const pass-by-value jest bezużyteczny i w najlepszym razie wprowadzający w błąd."From GOTW006
  • ale możesz je dodać w .cpp tak jak przy zmiennych.
  • zauważ, że biblioteka standardowa nie używa const. Np. std::vector::at(size_type pos). To, co jest wystarczająco dobre dla standardowej biblioteki, jest dobre dla mnie.
 2
Author: YvesgereY,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-26 09:36:52

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 odniesienia-nie jest to problem dla typów wbudowanych). Jeśli parametr jest odniesieniem lub Wskaźnikiem, zwykle lepiej jest chronić pamięć odniesienia / Wskazywania, a nie sam wskaźnik (myślę, że nie można zrobić samego odniesienia const, nie, że ma to duże znaczenie, ponieważ nie można zmienić sędziego). To wydaje się dobre pomysł, aby chronić wszystko, co możesz jako const. Można go pominąć bez obawy popełnienia błędu, jeśli parametry są tylko PODs (w tym typy wbudowane) i nie ma szans, aby zmieniły się dalej wzdłuż drogi(np. w twoim przykładzie parametr bool).

Nie wiedziałem o tym .h/.deklaracja pliku cpp jest różna, 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 jest taki sam jak w przypadku zadeklaruj go jako const (pomijając optymalizacje). Pomaga to jednak pozyskać kompilator, który nie zmieni wartości zmiennej wewnątrz implementacji funkcji (.ccp). Może się to przydać w przypadku, gdy dziedziczysz po interfejsie, który umożliwia zmianę, ale nie musisz zmieniać parametru, aby osiągnąć wymaganą funkcjonalność.

 1
Author: Attila,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:27:59

Nie umieszczałbym const na takich parametrach - wszyscy już wiedzą, że wartość logiczna (w przeciwieństwie do wartości logicznej&) jest stała, więc dodanie jej spowoduje, że ludzie pomyślą "czekaj, co?"lub nawet, że przekazujesz parametr przez odniesienie.

 0
Author: Khoth,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:17:44

Z const należy pamiętać, że o wiele łatwiej jest tworzyć rzeczy const od początku, niż próbować je później włożyć.

Użyj const, gdy chcesz, aby coś pozostało niezmienione - dodana podpowiedź opisuje, co robi twoja funkcja i czego się spodziewać. Widziałem wiele C API, które mogłyby zrobić z niektórych z nich, zwłaszcza te, które akceptują C-stringi!

Byłbym bardziej skłonny pominąć słowo kluczowe const w pliku cpp niż nagłówek, ale ponieważ mam tendencję do cięcia + wklejania trzymali by je w obu miejscach. Nie mam pojęcia, dlaczego kompilator na to pozwala, myślę, że to rzecz kompilatora. Najlepszą praktyką jest umieszczenie słowa kluczowego const w obu plikach.

 0
Author: gbjbaanb,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:18:00

Nie ma powodu, aby tworzyć wartość-parametr "const", ponieważ funkcja może zmodyfikować tylko kopię zmiennej.

Powodem użycia "const" jest to, że przekazujesz coś większego (np. strukturę z wieloma członkami) przez odniesienie, w którym to przypadku zapewnia to, że funkcja nie może tego zmodyfikować; lub raczej kompilator będzie narzekał, jeśli spróbujesz zmodyfikować ją w konwencjonalny sposób. Zapobiega to przypadkowej modyfikacji.

 0
Author: MarkR,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:19:35

Parametr Const jest użyteczny tylko wtedy, gdy parametr jest przekazywany przez referencję, tzn. albo referencję, albo wskaźnik. Gdy kompilator widzi parametr const, upewnia się, że zmienna użyta w parametrze nie jest modyfikowana w ciele funkcji. Dlaczego ktoś chciałby, aby parametr by-value jako stała? :-)

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-22 20:27:49

Ponieważ parametry są przekazywane przez wartość, nie ma znaczenia, czy określisz const czy nie z funkcji wywołującej perspective.It zasadniczo nie ma sensu deklarowanie parametrów pass by value jako const.

 0
Author: ,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2008-09-23 11:37:48

Wszystkie const w Twoich przykładach nie mają żadnego celu. C++ jest domyślnie pass-by-value, więc funkcja pobiera kopie tych ints i booleans. Nawet jeśli funkcja je zmodyfikowała, Kopia wywołującego nie jest naruszona.

Więc unikałbym dodatkowych const Bo

  • są redudant
  • One zaśmiecają tekst
  • uniemożliwiają mi zmiana wartości przekazanej w przypadki, w których może to być przydatne lub skuteczne.
 0
Author: AShelly,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-05-04 18:20:20

Wiem, że pytanie jest" trochę " nieaktualne, ale jak się z nim zapoznałem, ktoś inny może to zrobić w przyszłości... ...nadal wątpię, żeby biedak tu się znalazł, żeby 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, nie typami. Obiekt Const może być koncepcyjnie różny od obiektu nie-const, w szczególności w sensie logicznego-const (w przeciwieństwie do bitowego-const). Tak więc nawet jeśli const poprawność funkcji params jest (być może) nadmierną starannością w przypadku strąków, nie jest tak w przypadku obiektów. Jeśli funkcja działa z obiektem const, powinna tak powiedzieć. Rozważ następujący fragment kodu
#include <iostream>

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
class SharedBuffer {
private:

  int fakeData;

  int const & Get_(int i) const
  {

    std::cout << "Accessing buffer element" << std::endl;
    return fakeData;

  }

public:

  int & operator[](int i)
  {

    Unique();
    return const_cast<int &>(Get_(i));

  }

  int const & operator[](int i) const
  {

    return Get_(i);

  }

  void Unique()
  {

    std::cout << "Making buffer unique (expensive operation)" << std::endl;

  }

};

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void NonConstF(SharedBuffer x)
{

  x[0] = 1;

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void ConstF(const SharedBuffer x)
{

  int q = x[0];

}

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
int main()
{

  SharedBuffer x;

  NonConstF(x);

  std::cout << std::endl;

  ConstF(x);

  return 0;

}

Ps.: można argumentować, że odniesienie (const) byłoby bardziej odpowiednie tutaj i daje takie samo zachowanie. No tak. Po prostu daje inny obraz niż to, co mogłem zobaczyć gdzie indziej...

 -1
Author: PavDub,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-04-08 09:14:41