Czy czytelność jest ważnym powodem, aby nie używać const w parametrach (referencyjnych)?

24

Podczas pisania niektórych funkcji znalazłem słowo kluczowe const w parametrach takich jak to:

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
}

często powoduje podział linii na 2 linie w IDE lub vimie, więc chcę usunąć wszystkie słowa kluczowe const w parametrach:

void MyClass::myFunction(MyObject& obj,string& s1,string& s2,string& s3){
} 

czy to ważny powód, aby nie używać const? Czy utrzymywanie obiektów parametrów pozostaje niezmienione ręcznie?

grgrr
źródło
110
„Hej, chcę funkcjonalnie zmienić mój program”, aby uczynić go bardziej czytelnym to zły zły powód.
Pieter B
37
Program i tak nie jest już bardziej czytelny - gdy zobaczysz, że coś zostało przekazane, ponieważ constmasz silną wskazówkę, że nie musisz się martwić, jak można to zmienić w funkcji.
tofro
43
Lepszym sposobem na poprawę czytelności jest ograniczenie liczby argumentów.
5gon12eder
15
„const” prawdopodobnie poprawia czytelność. To stwierdzenie wyjaśnia, że ​​obj nie może się zmienić!
Charles
14
Aby poprawić czytelność, należy dodać spację po każdym przecinku.
sam hocevar

Odpowiedzi:

182

Czytelność jest ważnym powodem, aby nauczyć się korzystać z białych znaków:

void MyClass::myFunction(
        const MyObject& obj,
        const string& s1,
        const string& s2,
        const string& s3
) {
    return;
}

Umieszczone tam parametry nie będą mylone z treścią funkcji. Lokalizując je w innym wierszu, nie będziesz musiał zmieniać ich położenia, gdy zmienisz nazwę myFunctionna coś bardziej opisowego. Nie zmienianie pozycji parametrów, gdy nie uległy zmianie, jest czymś, co docenią użytkownicy narzędzia do kontroli źródła.

constcoś znaczy Nie wyrzucaj tego tylko dlatego, że brakuje Ci miejsca i pomysłów. Czytelność jest królem, ale łamanie rzeczy w imię jest po prostu rezygnacją.

candied_orange
źródło
6
„nie będziesz musiał zmieniać ich położenia po zmianie nazwy myFunction” - chociaż w tym przypadku wygląda na to, że zostały one ustawione w przybliżeniu w jednej linii z otworem (, a jeśli tak, to być może będziesz musiał zmienić położenie je, jeśli długość nazwy klasy + funkcji zmienia się o więcej niż około 4 znaki. Jeśli więc nie chcesz tego robić, dodaj stałą liczbę poziomów wcięcia, a nie liczbę zależną od długości nazwy funkcji. Poleciłbym 1 poziom, ta odpowiedź używa 6, ale każda stała liczba osiąga wyznaczony cel :-)
Steve Jessop
6
@CandiedOrange Dziwię się, że nie użyłeś „formularza 6” w tej odpowiedzi ... jest to zdecydowanie mniej brzydkie!
svidgen
6
Formularz 6 do wygranej. Jeden obszar tabulacji dla jednego poziomu wcięcia. Prosty i skuteczny. Problem rozwiązany :)
Wyścigi lekkości z Moniką
2
Ok, ok, forma 6. Jest to wariant, o którym wspominał JeffGrigg na C2.
candied_orange
4
@ random832 Wydaje mi się, że jesteśmy teraz mocno na terenie wiaty rowerowej. Oto właściwy sposób rozwiązania tego problemu: wyszukaj w kodzie przykłady, skonsultuj przewodnik po stylach sklepów, zapytaj programistów w swoim sklepie, a jeśli żadna z tych odpowiedzi nie przyniesie wiarygodnej odpowiedzi, skorzystaj z tego. Rozwiąż spory, które mogą iść w jedną stronę z jedną czwartą. Po wypowiedzeniu kwartału bądź konsekwentny!
candied_orange
52

W rzeczywistości kwestia czytelności zdecydowanie idzie w innym kierunku. Po pierwsze, możesz w prosty sposób rozwiązać swoją linię run-on, używając białych znaków . Ale usunięcie constnie tylko powoduje, że linia jest krótsza, ale całkowicie zmienia znaczenie programu.

Herb Sutter odnosi się constdo consttego, co najważniejsze,const ponieważ odniesienie do constmoże wiązać się z chwilowym i przedłużyć jego żywotność. Odwołanie do wartości nie constjest niemożliwe, potrzebujesz osobnej zmiennej.

void foo_const(std::string const& );
void foo_nc(std::string& );

std::string some_getter();

foo_const(some_getter());      // OK
foo_const("Hello there"); // OK

foo_nc(some_getter()); // error
foo_nc("Nope");   // error

std::string x = some_getter(); // have to do this
foo_nc(x);                     // ok
std::string msg = "Really??";  // and this
foo_nc(msg);                   // ok

Dla użyteczności oznacza to, że będziesz musiał wprowadzić wszystkie te zmienne tymczasowe, aby móc wywołać swoją funkcję. To nie jest świetne dla czytelności, ponieważ te zmienne są bez znaczenia i istnieją tylko dlatego, że twoja sygnatura jest błędna.

Barry
źródło
6
Twój drugi akapit sprawia mi ból głowy, gdy próbuję dowiedzieć się, czy constodnosi się constdo drugiego, consta co constnajważniejszeconst
Mindwin
3
@Mindwin Myślę, że ironia polega na tym, że mój drugi akapit jest jasny i jednoznaczny i nie mam pojęcia, o czym mówisz.
Barry
2
@Barry Z pewnością jest to jednoznaczne, ale zajęło mi kilka lektur tego akapitu, aby dowiedzieć się, co to znaczy. Myślę, że część problemu polega na tym, że można je przeanalizować „Herb Sutter odnosi się do const (w odniesieniu do const) jako najważniejszego const ...” lub „Herb Sutter odnosi się do const in (odniesienie do const) jako najbardziej ważny const ... „Uważam, że to ostatnie jest jedyną prawidłową grupą słów, ale ich przetworzenie zajmuje trochę czasu. Może istnieje sposób na użycie cudzysłowu w celu usunięcia niejasności?
Cort Ammon - Przywróć Monikę
1
Myślę, że niektóre związki z dzielonymi związkami to wyjaśnią.
shawnt00
2
lub konkretnie używaj tam const&zamiast odwoływania się constjako rzeczownik (fraza)
Caleth
21

Prosta odpowiedź brzmi „nie”.

Długa odpowiedź brzmi: constsłowo kluczowe jest częścią umowy, którą oferuje funkcja; informuje, że argument nie zostanie zmodyfikowany. W momencie usunięcia constgwarancji ta znika z okna. Pamiętaj, że nie można zasadnie utrzymywać constness (lub innego mienia) coś za pomocą dokumentacji, zjazdy, lub wytyczne - jeśli constness nie jest wymuszana przez kompilator, ktoś będzie myśleć, że mogą uczynić swoją pracę łatwiej, jeśli bawić z parametr „tylko trochę”. Rozważać:

// parameter "foo" is not modified
void fna(Foo& foo);

void fnb(const Foo& foo);

Oprócz tego, że ta ostatnia wersja jest bardziej zwięzła, zapewnia również silniejszą umowę i pozwala kompilatorowi pomóc w utrzymaniu twoich intencji. Ten pierwszy nie robi nic, aby uniemożliwić fna(Foo&)funkcji zmodyfikowanie przekazywanego parametru.

Podobnie jak w odpowiedzi @CandiedOrange, możesz użyć białych znaków, aby ułożyć kod i zwiększyć czytelność.

Mael
źródło
14

Usunięcie constsłowa kluczowego usuwa czytelność, ponieważ constprzekazuje informacje do czytnika i kompilatora.
Zmniejszenie długości kodu w poziomie jest dobre (nikt nie lubi przewijania w bok), ale jest coś więcej constniż tekst. Możesz to przepisać:

typedef string str;
typedef MyObject MObj;
void MyClass::myFunction(const MObj& o,const str& s1,const str& s2,const str& s3)

Co nie zmienia umowy, ale spełnia potrzebę zmniejszenia długości linii. Naprawdę uważałbym powyższy fragment za mniej czytelny i wybrałbym użycie większej ilości białych znaków, jak już wspomniano w odpowiedzi CandiedOrange.

constjest funkcją samego kodu. Nie spowodowałbyś, że funkcja nie byłaby członkiem w celu usunięcia MyClass::sekcji deklaracji, więc nie usuwajconst

Erdrik Ironrose
źródło
4
Zgadzam się, że podany fragment kodu jest mniej czytelny. Zmusza czytelnika, aby przejść dowiedzieć się co MObji strsą, a na pewno podnosi brwi. Jest to szczególnie dziwne w przypadku typów, nad którymi już masz kontrolę: np. Dlaczego nie nazwałeś MyObjecttak MObjna początek?
Jason C
3

Czy czytelność jest ważnym powodem, aby nie używać const w parametrach?

Nie. Pominięcie constmoże zmienić funkcjonalność, utracić zabezpieczenia consti może potencjalnie stworzyć mniej wydajny kod.

Czy utrzymywanie obiektów parametrów pozostaje niezmienione ręcznie?

Zamiast spędzać czas na ręcznym tworzeniu kodu

void MyClass::myFunction(const MyObject& obj,const string& s1,const string& s2,const string& s3){
  //
}

Użyj narzędzi do automatycznego formatowania . Napisz funkcję zgodnie z jej wymaganiami funkcjonalnymi i pozwól, aby automatyczne formatowanie obsłużyło prezentację. Ręczne dostosowywanie formatowania nie jest tak wydajne, jak użycie automatycznego formatowania i wykorzystanie zaoszczędzonego czasu do poprawy innych aspektów kodu.

void MyClass::myFunction(const MyObject& obj, const string& s1, const string& s2, 
    const string& s3) {
  // 
}
chux - Przywróć Monikę
źródło
-1

Tak długo, jak to możliwe, lepiej zachować stałą widoczność. Znacznie poprawia to utrzymanie kodu (bez zgadywania, czy ta metoda zmienia moje argumenty).

Jeśli widzę wiele argumentów w metodzie, zmusza mnie to do rozważenia stworzenia jarona opartego na projekcie (Matrix, Pracownik, Prostokąt, Konto), który byłby znacznie krótszy, łatwiejszy do zrozumienia (eliminuje długą listę argumentów do metod).

czarny długopis
źródło
Zgoda. Wahałem się, czy to wskazać. Zatem „ekstremalny przypadek”.
blackpen
@cmaster To powiedziawszy, czasami w pewnych kontekstach, z pewnymi programistami, może pozostać czytelne. Na przykład w bardzo szczególnym przypadku programu sięgającego głęboko w wywołania API systemu Windows, z czytnikiem, który jest przyzwyczajony do tego środowiska, rzeczy takie jak np. typedef Point * LPPOINTI typedef const Point * LPCPOINTchociaż bardzo wstrętne, nadal ma ukryte znaczenie, ponieważ jest zgodne z bezpośrednimi oczekiwaniami w kontekście. Ale nigdy w ogólnym przypadku; to tylko dziwny wyjątek, o którym mogę myśleć.
Jason C
1
Tak, kiedy zobaczyłem pytanie: „const unsigned long long int” przyszło mi do głowy, ale nie jest dobrym kandydatem do czerpania korzyści z bycia „const” lub „referencją”. Typedef rozwiązuje ogólny problem skracania nazw; ale nie wydaje się, aby dobry projekt ukrywał za sobą cel konstrukcji językowych (takich jak „const”).
blackpen