Jak stałeś się konwerterem stałej poprawności? [Zamknięte]

25

Po 15 latach C ++ wciąż nie nauczyłem się kochać używając const. Rozumiem, że jest użyteczny, ale tak naprawdę nigdy nie byłem w sytuacji, w której bycie nieustępliwym uniknęłoby problemu, z którym miałem do czynienia.

Jak więc pokochałeś zalety consts?

grok
źródło
3
Sądzę, że const poprawność polega raczej na byciu poprawnym niż na narzędziu służącym do rozwiązania problemu, takiego jak operator skurczu lub operator wielkości.
legends2k
9
„Powodem, dla którego const działa w C ++, jest to, że możesz go odrzucić. Jeśli nie możesz go odrzucić, wtedy twój świat będzie do dupy.” - Anders Hejlsberg
Mason Wheeler
1
const jest również modyfikatorem typu C i istnieje od pierwszego standardu ANSI C.
Huperniketes
Jestem rozpieszczany przez Javę / C #, jestem typem paranoika, który uwielbia odejść i zapewnia każdą szansę. Co może pójść nie tak, pójdzie nie tak. Jeśli istnieje asysta w czasie kompilacji lub w czasie wykonywania, licz mnie! Zostałem konwerterem, gdy tylko o nim usłyszałem 3-4 razy, i podążyłem za fragmentem tego linku (wystarczy, aby zobaczyć składnię, nie musiałem czytać o tym, dlaczego): ewentualność.com / Cpp / const.html Tylko dlatego, że coś jeszcze nie wybuchło mi w twarz ... nie trzeba się wysilać, aby być poprawnym i nie boli. Sprawdź przemyślenia Joela: joelonsoftware.com/articles/Wrong.html
Job

Odpowiedzi:

28

Cóż, nie byłem przekonany, dopóki nie spróbowałem przyjąć filozofii.

Najpierw zacząłem od umieszczenia constargumentów moich najbardziej podstawowych członków klasy i funkcji członkowskich tylko do odczytu.

Stamtąd nie mogłem już kompilować. Potem wytrwałem, wchodząc w kod przy użyciu tych podstawowych klas, sprawdzając, czy wcześniej constdodane dodatki były naprawdę uzasadnione w porównaniu do ich wykorzystania. Pomogło mi to naprawić kilka błędów po drodze, dodając ciągłość do innych części kodu.

To jest zaraźliwe. Większość kodu zyskała jeszcze większą spójność i łatwiej mi było go debugować, ponieważ daje pewność, że kompilator zatrzyma cię, jeśli zaczniesz modyfikować coś, czego nie powinieneś.

Gdy ponownie uruchomiłem aplikację, była szybsza (musiałam zmienić niektóre algorytmy, które, jak odkryłam, nie były odpowiednie do tego zadania), z dużo mniejszą liczbą błędów i łatwiejsza do zrozumienia podczas czytania kodu.

Byłem przekonany.

Teraz uważam, że jest jeszcze lepiej, gdy używasz wielu asercji oprócz constness, ponieważ to daje poczucie pewności, kiedy musisz napisać nowy kod lub zmodyfikować bieżący kod. Wiesz, że kompilator zatrzyma cię w razie potrzeby. Pozwala zapomnieć o sprawdzaniu wszystkiego, czego nie należy modyfikować, a wtedy masz więcej czasu na myślenie bardziej biznesowe lub architektoniczne.

Klaim
źródło
8
+1 za zaraźliwe, co w gruncie rzeczy oznacza, że ​​albo musisz stać się stałym nawróconym, albo całkowicie go unikać.
Martin Wickman,
Musisz także nie polegać na bibliotekach, które nie zapewniają stałej poprawności. Twoje podejście nie działa, gdy oznacza, że ​​nie możesz wywoływać żadnych funkcji GUI, ponieważ nie są one stałe - lub musisz je odrzucić w każdym wywołaniu GUI.
Martin Beckett
4
+1 dla „łatwiej jest debugować”, używam constnawet dla zmiennej lokalnej, o której wiem, że nie będę musiał jej zmieniać, w ten sposób podczas czytania kodu mogę przeskoczyć nad a iflub a forlub whatelse: moja zmienna jest stała, ja wiedz, że to się nie zmieni! Optymalizacje nie mniej mnie obchodziły, ale mam ograniczony mózg, a kilka poziomów wcięć + stała poprawność bardzo pomaga!
Matthieu M.
@MatthieuM .: Czy zastanawiałeś się kiedyś nad przejściem na Haskell? ;-)
Giorgio
@Giorgio: Odkryłem to, posunąłem się nawet do kupienia „Real World Haskell”. Szczerze mówiąc, domyślnie nie jestem podekscytowany lenistwem i wieloma tajemniczymi operatorami.
Matthieu M.
15

Nigdy nie byłem zwolennikiem programowania obiektowego, a jeśli cokolwiek się urosło, tym więcej dowiaduję się o programowaniu w ogóle. Jak już studiował różne paradygmaty programowania, zdałem sobie sprawę, że niezmienność jest jednym z centralnych pojęć projektowania programu, wpływając oprogramowanie napisane według dowolnego filozofii. Jest to niezwykle ważne w programowaniu funkcjonalnym, z implikacjami optymalizacji i współbieżności oprócz prostych gwarancji bezpieczeństwa.

Zasadniczo wszystko, co może być niezmienne, prawdopodobnie powinno być, chyba że masz dobry powód do zmiany stanu. Z mojego doświadczenia wynika, że ​​pisanie programów w dowolnym języku w celu osiągnięcia tego celu prowadzi do bezpieczniejszego, lepszego kodu. W constrazie potrzeby nie masz nic do stracenia - niezmienność jest darmowa!

(Nawiasem mówiąc, zastanawiałem się nad stworzeniem rozwidlenia GCC dla dialektu C ++, w którym wszystkie typy constnie są wyraźnie określone jako mutable. Jeśli istnieje wsparcie dla takiej rzeczy, całkowicie zobowiązuję się do jej utrzymania i używania.)


Z punktu widzenia OO niezmienność wymusza enkapsulację, uniemożliwiając nieograniczony dostęp do zapisu. Zmniejsza to sprzężenie między klasami, ponieważ obiekty niezmienne muszą w pełni zarządzać własnym stanem i tym samym zachowywać się jak zwykłe wartości. Const poprawność znacznie ułatwia proces sprawdzania poprawności programu, szczególnie w kontekście programowania współbieżnego. Dzięki semantyce referencji C ++ i semantyce referencji do wartości C ++ 0x możesz korzystać z niezmiennych obiektów bez obawy o koszty związane z kopiowaniem ich w dowolnym miejscu. Co więcej, kompilator może pracować z niesamowitą magią optymalizacji, jeśli pracujesz z najczęściej niezmiennymi obiektami.

Wiem, że pisanie constwszędzie jest do bani , ale szybko się do tego przyzwyczajasz, a korzyści stają się z czasem widoczne pod względem niezawodności i łatwości konserwacji. Nie jestem genialnym pisarzem i wydaje się, że udowodnienie tego jest trudnym zadaniem, ale wiem, że stała poprawność była bardzo pomocna dla mnie jako programisty przy projektowaniu i wdrażaniu programów i myślę, że doświadczenie jest najlepszy nauczyciel pod tym względem.

Jon Purdy
źródło
2
W zasadzie właśnie powiedziałeś, że stała poprawność jest Dobrą Rzeczą. Powiedziałeś, że „prowadzi to do bezpieczniejszego, lepszego kodu”. Czy możesz powiedzieć dlaczego?
David Reis,
Jestem całkowicie w obozie niezmienności, moim ulubionym językiem jest Erlang. Twierdziłbym jednak, że niezmienność przez const w C ++ nie jest naprawdę darmowa. Istnieją wady, takie jak mniej czytelny kod, wersje const i non const tej samej metody lub odrzucanie const powoduje, że „po prostu nie było innego wyboru”.
grok
1
Radziłbym nie tylko używać mutable, ponieważ ma to wyraźne znaczenie pod względem stałej poprawności. Oznacza to, że ten obiekt danych może się zmieniać w sposób, który nie wpływa na zachowanie obiektu, i umożliwia takie rzeczy, jak buforowanie odpowiedzi. Utwórz inne słowo kluczowe.
David Thornley,
2
@David Thornley: Dla zachowania mutablelogiki jest logicznym wyborem. void alter(mutable Point&)ma sens, podobnie jak mutable int foow przypadku zmiennej lokalnej, i żaden z tych konfliktów nie jest związany z istniejącym językiem ani z istniejącym użyciem mutable. Również Object mutable* mutablewygląda groźnie wystarczy być ostrzeżenie o tym, czy jest to konieczne lub właściwe.
Jon Purdy,
Jeśli kiedykolwiek wykonasz rozwidlenie, zastanów się zamiast tego z CLang - powinno być mniej bolesne.
gf
6

Zaletą stałej poprawności jest to, że nakłada dyscyplinę na program i ułatwia rozumowanie na temat części programu.

Dyscyplina polega na tym, że musisz wiedzieć, gdzie coś może się zmienić. Odpowiednią zaletą jest to, że łatwiej jest zobaczyć, co robi kawałek kodu, gdy można stwierdzić, co może zmienić stan.

David Thornley
źródło
1
„Programy muszą być pisane, aby ludzie mogli je czytać, a tylko przypadkowo, aby maszyny mogły je uruchomić”. - Abelson i Sussman, SICP
Brandon DuRette
4

Bycie const poprawnym podkreśla poprawność projektu, który traktuję blisko podobnej kwestii, która nie polega na użyciu operatorów rzutowania; więc nie używanie rzutowania i ciągła poprawność, minimalne użycie zmiennych - wszystkie są wskaźnikami do pomiaru, jak dobry jest projekt ale nie rzeczywistymi narzędziami do rozwiązania ogólnego problemu.

PS: Całkowicie przekonałem się, constkiedy zrozumiałem poprawność korzystania z niego;)

legends2k
źródło
2

Widzę dwa główne powody pisania poprawnego kodu. Jednym z nich jest to, że kompilator jest twoim przyjacielem i za pomocą const pozwalasz mu ostrzegać przed potencjalnymi błędami. Drugim powodem jest to, że poprawność stałej sprawia, że ​​kod jest bardziej czytelny. Na przykład zawsze wiesz, które argumenty funkcji są wejściami, a które wyjściami. Wiesz także, które funkcje składowe modyfikują obiekt, a które nie. Znasz te rzeczy natychmiast, bez konieczności czytania kodu. Zakłada to oczywiście bardzo rozsądne użycie const_cast.

Dima
źródło
2

Byłem nawrócony, gdy tylko wiedziałem, że to możliwe. To miało dla mnie sens z punktu widzenia „dobrego stylu programowania”. Istnieje wiele powodów, dla których dobrą praktyką jest ciągłe poprawianie:

  • Czytelność i zrozumienie. Jeśli czytam kod innej osoby, a funkcja przyjmuje stałe odwołanie jako parametr, wiem, że parametr ten służy wyłącznie jako zmienna tylko do odczytu. Jest to ogromna wygrana, szczególnie jeśli kod jest środowiskiem wielowątkowym.
  • Kompilator może korzystać z kwalifikatora const, aby ułatwić przebieg optymalizacji.
  • Powiedzmy, że mam obiekt klasy A w sytuacji, gdy nie chcę, żeby się zmienił. Zatem jedynymi funkcjami składowymi, które można wywołać dla tego obiektu, są te, które są const.
sashang
źródło
2

Aby podsumować dwa punkty, które zostały omówione w innych odpowiedziach, i dodaj nowy:

  • constdokumentuje kod użytkownikom interfejsu API. Tworzy umowę między funkcją a jej wywołującym, że funkcja nie będzie modyfikować swoich parametrów. (Należy pamiętać, że const_castnie pozwala funkcji na zmianę parametru, pozwala przekazać ten parametr do innych funkcji, które nie modyfikują swoich parametrów, ale zapomniały constadnotacji.) Jest to również przydatne w funkcjach / pętli / etc, ponieważ pomaga znacznie zrozumieć tak samo jak niezmiennik pętli.

  • constdokumentuje twoje zamiary w kompilatorze. Znalezienie błędów w czasie kompilacji jest zawsze lepsze niż czekanie na uruchomienie tego fragmentu kodu.

  • constjest niezbędny do bezpiecznego polimorfizmu typu. Wskaźniki (we wszystkich swoich postaciach, nie tylko surowe wskaźniki) są kowariantne tylko wtedy, gdy są const(Uwaga: nie to samo, co „wskaźnik do stałej”). Kowariancja wymaga interfejsu tylko do odczytu, a kontrawariancja wymaga interfejsu tylko do odczytu.

Drugi z nich nauczyłem się pierwszy. Zacząłem constod samego celu wskaźnika i parametrów referencyjnych, dopóki nie zacząłem dostrzegać korzyści z wcześniejszego wychwytywania błędów i używania go na lokalnych, itp.

Potem dowiedziałem się, że większość #defines można zastąpić (w C ++) stałymi globalnymi, z dodatkowymi korzyściami bezpieczeństwa typu. Więc też go tam wykorzystałem.

W końcu wziąłem klasę na temat systemów typów i rachunku lambda i dowiedziałem się, że consti nietypowe constsą zasadniczo różne (ponieważ obsługują różne operacje), i od tego czasu nigdy nawet nie rozważałem pisania kodu C ++ bez intensywnego użycia const.

Ben Voigt
źródło
1

Oto moje 5 centów tego, o czym inni nie wspominali. Przekazując zmienne, nie chcesz przekazywać wartości, chyba że naprawdę potrzebujesz, aby uniknąć dodatkowych konstrukcji, zniszczeń i kopii. Tak więc, chyba że naprawdę musisz przekazać wartość, używanie referencji wszędzie, nawet jeśli nie chcesz zmieniać przekazywanej wartości, to znaczny wzrost wydajności. Z tego powodu, gdy masz funkcje pobierające odwołania do wszystkich jej argumentów, musisz powiadomić program wywołujący, czego funkcja nie będzie modyfikować.

To ta sama zasada, ale chciałem tylko dodać praktyczny powód użycia const.

Nikiforos Rotas
źródło