Dzięki nowemu standardowi istnieją nowe sposoby robienia rzeczy, a wiele z nich jest ładniejszych niż stare sposoby, ale stary sposób jest nadal w porządku. Oczywiste jest również, że nowy standard nie jest oficjalnie bardzo przestarzały, ze względu na kompatybilność wsteczną. Pozostaje więc pytanie:
Jakie stare sposoby kodowania są zdecydowanie gorsze od stylów C ++ 11 i co możemy teraz zamiast tego zrobić?
Odpowiadając na to, możesz pominąć oczywiste rzeczy, takie jak „użyj zmiennych automatycznych”.
auto_ptr
jest również przestarzałe.Odpowiedzi:
final
specyfikator zapobiegający wyprowadzaniu klasstd::auto_ptr
prace nie są już potrzebne ze względu na pierwszorzędne wsparcie dla odniesień do wartości.shrink_to_fit()
elementu członkowskiego, co powinno wyeliminować potrzebę tymczasowej zamiany.= delete
Składnia jest znacznie bardziej bezpośrednim sposobem stwierdzenia, że konkretna funkcjonalność jest wyraźnie zabroniona. Ma to zastosowanie do zapobiegania przydziałowi stosu (tj.=delete
Dla członkaoperator new
), zapobiegania kopiowaniu, przypisaniu itp.result_of
: Zastosowania szablonu klasyresult_of
należy zastąpićdecltype
. Myślę, żeresult_of
używa,decltype
gdy jest dostępny.NULL
powinien zostać ponownie zdefiniowany jakonullptr
, ale zobacz przemówienie STL, aby dowiedzieć się, dlaczego zdecydowali się na to.Myślę, że się tam zatrzymam!
źródło
result_of
z listy. Mimo, żetypename
było to uciążliwe przedtem, myślę, żetypename result_of<F(Args...)::type
czasami może być łatwiejsze do odczytania niżdecltype(std::declval<F>()(std::declval<Args>()...)
, a po przyjęciu N3436 do dokumentu roboczego, oboje pracują dla SFINAE (co było zaletą,decltype
żeresult_of
nie oferowało)W pewnym momencie argumentowano, że należy zwracać
const
wartość, a nie tylko wartość:Było to w większości nieszkodliwe w C ++ 98/03 i mogło nawet wykryć kilka błędów, które wyglądały następująco:
Ale powrót przez
const
jest przeciwwskazany w C ++ 11, ponieważ hamuje semantykę ruchu:Po prostu zrelaksuj się i napisz:
źródło
A& operator=(A o)&
zamiastA& operator=(A o)
. Zapobiegają głupim błędom i sprawiają, że klasy zachowują się bardziej jak podstawowe typy i nie zapobiegają semantyce ruchów.Jak najszybciej możesz porzucić
0
iNULL
na korzyśćnullptr
, zrób to!W kodzie nieogólnym użycie
0
lubNULL
wcale nie jest takie duże. Ale gdy tylko zaczniesz przekazywać wartości stałe wskaźnika zerowego w kodzie ogólnym, sytuacja szybko się zmienia. Gdy przejdziesz0
do a,template<class T> func(T)
T
zostanie wydedukowane jakoint
stała zerowa, a nie jako stała zerowa. Po tym nie można go przekształcić z powrotem w stałą wskaźnika zerowego. Spada to w bagno problemów, które po prostu nie istnieją, gdyby tylko wszechświat go używałnullptr
.C ++ 11 nie jest przestarzałe
0
iNULL
jako stałe wskaźnika zerowego. Ale powinieneś kodować tak, jakby to zrobił.źródło
std::nullptr_t
.0
lub „NULL
dla zerowych”).Bezpieczny idol bool →
explicit operator bool()
.Konstruktory kopii prywatnych (boost :: noncopyable) →
X(const X&) = delete
Symulowanie końcowej klasy za pomocą prywatnego destruktora i wirtualnego dziedziczenia →
class X final
źródło
Jedną z rzeczy, które po prostu unikają pisania podstawowych algorytmów w C ++ 11, jest dostępność lambd w połączeniu z algorytmami zapewnianymi przez standardową bibliotekę.
Używam ich teraz i to niewiarygodne, jak często mówisz, co chcesz zrobić, używając count_if (), for_each () lub innych algorytmów zamiast pisać ponownie cholerne pętle.
Kiedy używasz kompilatora C ++ 11 z pełną biblioteką standardową C ++ 11, nie masz już żadnej wymówki, by nie używać standardowych algorytmów do budowania własnych . Lambda po prostu go zabij.
Czemu?
W praktyce (po tym, jak sam użyłem tego sposobu pisania algorytmów), znacznie łatwiej jest przeczytać coś, co jest zbudowane z prostych słów oznaczających to, co się dzieje, niż z niektórymi pętlami, które musisz odszyfrować, aby poznać znaczenie. To powiedziawszy, automatyczne obliczanie argumentów lambda bardzo pomogłoby uczynić składnię łatwiejszą do porównania z surową pętlą.
Zasadniczo algorytmy odczytu wykonane przy użyciu standardowych algorytmów są znacznie łatwiejsze, ponieważ słowa ukrywające szczegóły implementacji pętli.
Zgaduję, że należy teraz myśleć tylko o algorytmach wyższego poziomu, ponieważ mamy algorytmy niższego poziomu do zbudowania.
źródło
for_each
z lambda była lepsza niż równoważna pętla oparta na zakresie, z zawartością lambda w pętli. Kod wygląda mniej więcej tak samo, ale lambda wprowadza dodatkową interpunkcję. Możesz użyć ekwiwalentów rzeczy, takich jakboost::irange
zastosowanie go do większej liczby pętli niż tylko te, które oczywiście używają iteratorów. Ponadto pętla oparta na zakresie ma większą elastyczność, dzięki czemu możesz wyjść wcześniej, jeśli jest to wymagane (przezreturn
lub przezbreak
), podczas gdyfor_each
musisz rzucić.for
powoduje, że zwykłyit = c.begin(), const end = c.end(); it != end; ++it
idiom nie działa .for_each
algorytmu w stosunku do zakresu opartego na pętli jest to, że nie możeszbreak
lubreturn
. Oznacza to, że kiedy widziszfor_each
, natychmiast wiesz, nie patrząc na ciało, że nie ma takiej podstępu.std::for_each(v.begin(), v.end(), [](int &i) { ++i; });
zfor (auto &i : v) { ++i; }
. Akceptuję, że elastyczność jest obosieczna (goto
jest bardzo elastyczna, to jest problem). Nie sądzę, że ograniczenie wynikające z niemożności użyciabreak
wfor_each
wersji rekompensuje dodatkową gadatliwość, jakiej wymaga -for_each
tutaj użytkownicy IMO poświęcają rzeczywistą czytelność i wygodę dla pewnego rodzaju teoretycznego pojęcia, żefor_each
jest to w zasadzie jaśniejsze i koncepcyjnie prostsze. W praktyce nie jest to ani jaśniejsze ani prostsze.Będziesz musiał wdrażać niestandardowe wersje
swap
rzadziej. W C ++ 03swap
często konieczne jest wydajne nie rzucanie, aby uniknąć kosztownych i rzucających kopii, a ponieważstd::swap
używa dwóch kopii,swap
często trzeba je dostosować. W C ++std::swap
używamove
, więc skupiono się na wdrażaniu wydajnych i nie rzucających konstruktorów ruchów i operatorów przypisań ruchów. Ponieważ dla tych wartości domyślnych często jest dobrze, będzie to o wiele mniej pracy niż w C ++ 03.Zasadniczo trudno jest przewidzieć, które idiomy zostaną użyte, ponieważ są tworzone przez doświadczenie. Możemy spodziewać się „Skutecznego C ++ 11” może w przyszłym roku, a „Standardów kodowania C ++ 11” tylko za trzy lata, ponieważ nie ma jeszcze niezbędnego doświadczenia.
źródło
Nie znam jego nazwy, ale kod C ++ 03 często używał następującej konstrukcji jako zamiennika brakującego przypisania ruchu:
Pozwoliło to uniknąć kopiowania z powodu usunięcia kopii w połączeniu z
swap
powyższym.źródło
map
. Technika, którą pokazujesz, jest przydatna, jeślimap
już istnieje, a nie tylko w jej konstrukcji. Przykład byłby lepszy bez komentarza „tani domyślny konstruktor” i z „// ...” pomiędzy tą konstrukcją a zamianąKiedy zauważyłem, że kompilator korzystający ze standardu C ++ 11 nie powoduje już błędu następującego kodu:
za rzekomo zawierający operator >> zacząłem tańczyć. We wcześniejszych wersjach trzeba było to zrobić
Co gorsza, jeśli kiedykolwiek musiałeś to debugować, wiesz, jak przerażające są komunikaty o błędach, które z tego wynikają.
Nie wiem jednak, czy było to dla ciebie „oczywiste”.
źródło
Zwrot według wartości nie stanowi już problemu. Z semantyką ruchu i / lub optymalizacją wartości zwracanych (zależnych od kompilatora) funkcje kodowania są bardziej naturalne, bez kosztów ogólnych i kosztów (przez większość czasu).
źródło