Krótkie pytanie na temat używania/nadużywania const w programie

0

Ostatnio wzięło mnie na pisanie w C++. W szczególności pisanie ładnego kodu w C++.

Stąd też krótkie pytanie - preferujecie:

int foo(int bar, const int &baz)
{
    int apple = bar + baz; // obowiązkowa zmienna pomocnicza
    return apple + 2;
}

czy raczej coś w rodzaju:

const int foo(const int bar, const int &baz)
{
    const int apple = bar + baz; // obowiązkowa <del>zmienna</del> stała pomocnicza
    return apple + 2;
}

(tzn. const gdzie się tylko da)

0

Raczej pierwsze podejście, w imię zasady "nadgorliwość gorsza od faszyzmu".

0

Moim zdaniem apple powinno być const int, pozostałe dodane const nie mają sensu. Z tego właśnie powodu const wsadzam tam, gdzie ma to sens, tzn. coś jest stałe i powinno być.

2

Ja wrzucam dużo constów. Zmniejsza to ilość błędów, które powstają. I to nie jest żadna nadgorliwość, tylko zmniejszenie sobie roboty przy testowaniu.

Ostatnio mam też tendencję do wpisywania const między typ, a nazwę. Dzięki temu przy konstrukcjach typu: <<< typ [const] * [const] nazwa >>>, od razu widzę, co jest stałe, tzn czy sam wskaźnik, czy też/ lub to na co wskazuje.

Na pewno nie szczędziłbym constów przy publicznym API. STL ma zdaje się górę constów w publicznym API. Jeżeli funkcja nie modyfikuje obiektu to daj consta. Dzięki temu będziesz mógł np odpalić length() na stałym obiekcie. Nie-const automatycznie rzutuje się na const, natomiast w drugą stronę już jest kombinowanie i obchodzenie mechanizmów C++ (co może doprowadzić do katastrofy).

http://en.wikipedia.org/wiki/Const-correctness
Zdaje mi się, że głębokie consty i immutable w D mają znacznie więcej sensu niż płytkie consty z C/C++.

Jeszcze jedna sprawa:

int const lokalnaStała = 5;
if (lokalnaStała = 6) cośtam;

nie skompiluje się, natomiast:

int lokalnaNibyStała = 5;
if (lokalnaNibyStała = 6) cośtam;

skompiluje się i program będzie zawierał błąd.

0

Raczej nie ma większego sensu const przy apple, zmienna lokalna, więc nie ma specjalnie ryzyka. Za to przy baz skoro ma nie być zmieniana to naprawdę wypada dać const.

//zgadzam się z powyższym, wszystko co publiczne niech ma jak najwięcej const'ów, od razu widać czego można się spodziewać po funkcji/metodzie.

0

Według mnie - zależy co chcesz potem robić z tym kodem. Jeśli jest tylko dla Ciebie - ja bym się nie bawił w consty. Sam najlepiej wiesz, co można ruszyć, a czego nie. Podobnie z private/public (private ustawiam tylko po to, by intellisense mi nie wyświetlało wielkiej listy xD)

0

Używam constów wszędzie, ale nie w parametrach formalnych. Tzn mam na myśli parametry typu int czy float. przy wskaźnikach i referencjach oczywiście tak.
Z innych praktyk, to wolę uint lub size_t zamiast int.

0

Najważniejszy jest const przy referencjach. Twój przykład nie pozwala pokazać dlaczego.

int doThings(const std::string& a);

Bez const takie coś nie zadziała:

a = doThings("tada - automatyczna konwersja")

Jak mówi Karolaq dla argumentów o typach prostych zwykle nie ma sensu stosować const. Dla wszelkich obiektów ma już to sens.

W zasadzie można żyć bez const, np jego użycie zostało bardzo zredukowane w C# i moim zdaniem jest to bardzo rozsądne podejście.

0

Zredukowane w C#? C# to kalka Javy, a Javowe final to chyba najsłabsze stałe z wszystkich modnych języków.

Const przy parametrach wszelakich funkcji jest przydatne wg mnie z tego względu, że wiem co dany parametr oznacza i nie muszę szukać po funkcji, czy gdzieś nie został zmieniony.

0

@Wibowit: A czy ma dla Ciebie znaczenie czy parametr typu int się zmienia w funkcji?
Ja powiem szczerze, że ciężko mi wypracować odpowiednią konwencję dla typów prostych. Z jednej strony w implementacji daję const i nie patrzę, jaki to typ. Z drugiej strony parametry formalne zaczynają stanowić problem. Bo raz int byłby typu const, a raz nie. zależne od implementacji. Taki trochę śmietnik.

A tak zmieniając temat: która pętlę preferujecie?

int main()
{
    const size_t size = 10;
    int tab[size];

    for(int i = 0; i < size; ++i)
        tab[i] = 1;

    for(uint i = 0; i < size; ++i)
        tab[i] = 2;

    for(size_t i = 0; i < size; ++i)
        tab[i] = 3;

    return 0;
}
0

Karolak:
Parametr jest zmienną lokalną, więc dotyczą go te same wady co zmiennych lokalnych. Przytoczę jeden, o którym już w tym wątku napisałem:

if (parametr = 5) cośtam

Ten kod się skompiluje i będzie działał błędnie tylko wtedy, gdy nie zastosuję const do parametru.

0

Akurat na takie błędy nie patrzę, bo od tego mam kompilator.

No właśnie z jednej strony niby jest zmienną lokalna, ale z drugiej powinien dawać jakieś sensowne informacje dla użytkownika funkcji. Przeglądałem źródła STL-a i zauważyłem, że myślą podobnie.

1 użytkowników online, w tym zalogowanych: 0, gości: 1