Często widzę w kodach C i C ++ następującą konwencję:
some_type val;
val = something;
some_type *ptr = NULL;
ptr = &something_else;
zamiast
some_type val = something;
some_type *ptr = &something_else;
Początkowo założyłem, że był to nawyk, który pozostał z czasów, kiedy trzeba było zadeklarować wszystkie zmienne lokalne na początku zakresu. Ale nauczyłem się nie odrzucać tak szybko nawyków doświadczonych programistów. Czy jest więc dobry powód, aby zadeklarować w jednym wierszu, a potem przypisać?
Odpowiedzi:
do
W C89 wszystkie deklaracje musiały znajdować się na początku zakresu (
{ ... }
), ale wymaganie to zostało szybko usunięte (najpierw z rozszerzeniami kompilatora, a później ze standardem).C ++
Te przykłady nie są takie same.
some_type val = something;
wywołuje konstruktor kopiowania, podczas gdyval = something;
wywołuje konstruktora domyślnego, a następnieoperator=
funkcję. Ta różnica jest często krytyczna.Zwyczaje
Niektóre osoby wolą najpierw zadeklarować zmienne, a później je zdefiniować, w przypadku, gdy formatują kod później z deklaracjami w jednym miejscu, a definicją w innym.
Jeśli chodzi o wskaźniki, niektórzy ludzie mają zwyczaj inicjować każdy wskaźnik do
NULL
lubnullptr
bez względu na to, co z nim robią.źródło
some_type
konstruktorsomething
jako jedyny argument. Jest to bardzo interesujący i niezwykły przypadek w C ++ ... oznacza, że istnieje domniemanie dotyczące semantycznego znaczenia tych operacji.Oznaczyłeś jednocześnie swoje pytanie C i C ++, podczas gdy odpowiedź jest znacząco różna w tych językach.
Po pierwsze, brzmienie tytułu pytania jest niepoprawne (a ściślej nie ma znaczenia dla samego pytania). W obu przykładach zmienna jest zadeklarowana i zdefiniowana jednocześnie, w jednym wierszu. Różnica między twoimi przykładami polega na tym, że w pierwszym zmienne są albo niezainicjowane, albo zainicjowane wartością zastępczą, a następnie przypisuje się im znaczącą wartość później. W drugim przykładzie zmienne są inicjowane od razu.
Po drugie, w języku C ++, jak zauważył @nightcracker w swojej odpowiedzi, te dwie konstrukcje są semantycznie różne. Pierwszy polega na inicjalizacji, a drugi na przypisaniu. W C ++ operacje te są przeciążalne i dlatego mogą potencjalnie prowadzić do różnych wyników (chociaż można zauważyć, że wytwarzanie nie równoważnych przeciążeń inicjalizacji i przypisywania nie jest dobrym pomysłem).
W oryginalnym standardowym języku C (C89 / 90) deklarowanie zmiennych w środku bloku jest nielegalne, dlatego na początku bloku można zobaczyć zmienne zadeklarowane jako niezainicjowane (lub zainicjowane wartościami zastępczymi), a następnie przypisane znaczącym wartości później, gdy te znaczące wartości staną się dostępne.
W języku C99 można zadeklarować zmienne w środku bloku (podobnie jak w C ++), co oznacza, że pierwsze podejście jest potrzebne tylko w niektórych szczególnych sytuacjach, gdy inicjator nie jest znany w punkcie deklaracji. (Dotyczy to również C ++).
źródło
some_type val;
natychmiast deklaruje i definiuje zmiennąval
. To właśnie miałem na myśli w mojej odpowiedzi.Myślę, że to stary nawyk, pozostałość po czasach „deklaracji lokalnej”. A zatem jako odpowiedź na twoje pytanie: Nie, nie sądzę, żeby był dobry powód. Nigdy tego nie robię.
źródło
Powiedziałem coś na ten temat w mojej odpowiedzi na pytanie Helium3 .
Zasadniczo mówię, że to wizualna pomoc, aby łatwo zobaczyć, co się zmieniło.
i
źródło
Inne odpowiedzi są całkiem dobre. W C. jest trochę historii. W C ++ istnieje różnica między konstruktorem a operatorem przypisania.
Dziwię się, że nikt nie wspomina o dodatkowej kwestii: oddzielenie deklaracji od użycia zmiennej może być czasem znacznie bardziej czytelne.
Mówiąc wizualnie, podczas czytania kodu, bardziej przyziemne artefakty, takie jak typy i nazwy zmiennych, nie są tym, co na ciebie wyskakuje. Są to stwierdzenia , które zazwyczaj najbardziej Cię interesują, spędzasz najwięcej czasu, wpatrując się w nie, a więc masz tendencję do zerkania na resztę.
Jeśli mam kilka typów, nazw i przydziałów, wszystko dzieje się w tej samej ciasnej przestrzeni, to trochę przeciążam informacje. Co więcej, oznacza to, że dzieje się coś ważnego w przestrzeni, na którą zwykle spoglądam.
Może to wydawać się nieco sprzeczne z intuicją, ale jest to jeden przypadek, w którym zwiększenie źródła zajmuje więcej miejsca w pionie. Uważam, że jest to podobne do tego, dlaczego nie powinieneś pisać wypełnionych dżemem linii, które wykonują szalone ilości arytmetyki wskaźnika i zadania w ciasnej pionowej przestrzeni - tylko dlatego, że język pozwala ci uciec od takich rzeczy, nie oznacza, że powinieneś to cały czas. :-)
źródło
W C była to standardowa praktyka, ponieważ zmienne musiały zostać zadeklarowane na początku funkcji, w przeciwieństwie do C ++, gdzie można je zadeklarować w dowolnym miejscu w ciele funkcji do późniejszego użycia. Wskaźniki zostały ustawione na 0 lub NULL, ponieważ po prostu upewniło się, że wskaźnik nie wskazuje śmieci. W przeciwnym razie nie mogę wymyślić żadnej znaczącej korzyści, która zmusiłaby każdego do takiego działania.
źródło
Zalety lokalizacji definicji zmiennych i ich znaczącej inicjalizacji:
jeśli zmiennym zwykle przypisuje się znaczącą wartość, gdy pojawiają się po raz pierwszy w kodzie (inna perspektywa na to samo: opóźniasz ich pojawienie się, dopóki znacząca wartość nie będzie dostępna), wówczas nie ma szans na przypadkowe użycie ich z wartością bez znaczenia lub niezainicjowaną ( co może się łatwo zdarzyć, jeśli inicjalizacja zostanie przypadkowo pominięta z powodu instrukcji warunkowych, oceny zwarcia, wyjątków itp.)
może być bardziej wydajny
operator=
czasami może być mniej wydajny i wymagać tymczasowego obiektuminimalizacja zakresu zmiennych z kolei minimalizuje średnią liczbę zmiennych w zakresie : to
czasami bardziej zwięzłe, ponieważ nie powtarzasz nazwy zmiennej w definicji, niż w początkowym znaczącym przypisaniu
niezbędne w przypadku niektórych typów, takich jak odwołania i gdy chcesz, aby obiekt był
const
Argumenty do grupowania definicji zmiennych:
czasami wygodne i / lub zwięzłe jest rozróżnienie rodzaju wielu zmiennych:
the_same_type v1, v2, v3;
(jeśli powodem jest to, że nazwa typu jest zbyt długa lub złożona,
typedef
czasem może być lepsza)czasami pożądane jest grupowanie zmiennych niezależnie od ich użycia, aby podkreślić zestaw zmiennych (i typów) zaangażowanych w niektóre operacje:
type v1;
type v2;
type v3;
Podkreśla to powszechność typów i ułatwia ich zmianę, przy jednoczesnym trzymaniu się zmiennej w wierszu, która ułatwia kopiowanie-wklejanie,
//
komentowanie itp.Jak to często bywa w programowaniu, podczas gdy jedna praktyka może przynieść wyraźną korzyść empiryczną w większości sytuacji, druga praktyka naprawdę może być zdecydowanie lepsza w kilku przypadkach.
źródło