Moim zdaniem niebezpieczeństwa związane z C ++ są nieco przesadzone.
Istotne niebezpieczeństwo jest następujące: podczas gdy C # pozwala wykonywać „niebezpieczne” operacje na wskaźnikach przy użyciu unsafe
słowa kluczowego, C ++ (będący przeważnie nadzbiorem C) pozwala używać wskaźników, kiedy tylko masz na to ochotę. Oprócz zwykłych zagrożeń związanych ze stosowaniem wskaźników (które są takie same w przypadku C), takich jak wycieki pamięci, przepełnienie bufora, zwisające wskaźniki itp., C ++ wprowadza nowe sposoby poważnego zepsucia.
Ta „dodatkowa lina”, że tak powiem, o której mówił Joel Spolsky , w zasadzie sprowadza się do jednej rzeczy: pisania zajęć, które wewnętrznie zarządzają własną pamięcią, znaną również jako „ Reguła 3 ” (którą można teraz nazwać Regułą 4 lub Reguła 5 w C ++ 11). Oznacza to, że jeśli kiedykolwiek chcesz napisać klasę, która wewnętrznie zarządza przydziałami pamięci, musisz wiedzieć, co robisz, w przeciwnym razie program prawdopodobnie się zawiesi. Musisz ostrożnie utworzyć konstruktor, skopiować konstruktor, destruktor i operator przypisania, co jest zaskakująco łatwe do popełnienia błędu, często powodując dziwne awarie w czasie wykonywania.
JEDNAK , w codziennym programowaniu w C ++, bardzo rzadko jest pisanie klasy, która zarządza własną pamięcią, więc mylące jest twierdzenie, że programiści C ++ zawsze muszą być „ostrożni”, aby uniknąć tych pułapek. Zwykle będziesz robić coś więcej:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
Ta klasa wygląda dość blisko tego, co robisz w Javie lub C # - nie wymaga jawnego zarządzania pamięcią (ponieważ klasa biblioteki std::string
zajmuje się tym wszystkim automatycznie) i nie jest wymagana żadna funkcja „Reguły 3”, ponieważ domyślna Konstruktor kopiowania i operator przypisania są w porządku.
Tylko wtedy, gdy próbujesz zrobić coś takiego:
class Foo
{
public:
Foo(const char* s)
{
std::size_t len = std::strlen(s);
m_name = new char[len + 1];
std::strcpy(m_name, s);
}
Foo(const Foo& f); // must implement proper copy constructor
Foo& operator = (const Foo& f); // must implement proper assignment operator
~Foo(); // must free resource in destructor
private:
char* m_name;
};
W takim przypadku nowicjuszom może być trudne uzyskanie poprawnego przypisania, destruktora i konstruktora kopiowania. Ale w większości przypadków nie ma powodu, aby to robić. C ++ sprawia, że bardzo łatwo jest uniknąć ręcznego zarządzania pamięcią przez 99% czasu, używając klas bibliotek takich jak std::string
i std::vector
.
Innym powiązanym problemem jest ręczne zarządzanie pamięcią w sposób, który nie bierze pod uwagę możliwości zgłoszenia wyjątku. Lubić:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
Jeśli some_function_which_may_throw()
faktycznie nie wyjątek, jesteś w lewo z wyciekiem pamięci, ponieważ pamięć przeznaczona na s
nigdy nie zostaną odzyskane. Ale znowu, w praktyce nie jest to już problemem z tego samego powodu, dla którego „Reguła 3” nie jest już tak naprawdę dużym problemem. Bardzo rzadko (i zwykle nie jest to konieczne) zarządzanie własną pamięcią za pomocą surowych wskaźników. Aby uniknąć powyższego problemu, wystarczy użyć std::string
lub std::vector
, a destruktor zostanie automatycznie wywołany podczas rozwijania stosu po zgłoszeniu wyjątku.
Tak więc ogólnym tematem jest to, że wiele funkcji C ++, które nie zostały odziedziczone po C, takich jak automatyczna inicjalizacja / niszczenie, konstruktory kopiowania i wyjątki, zmusza programistę do zachowania szczególnej ostrożności podczas ręcznego zarządzania pamięcią w C ++. Ale znowu jest to problem tylko wtedy, gdy zamierzasz ręcznie zarządzać pamięcią, co nie jest już prawie konieczne, gdy masz standardowe pojemniki i inteligentne wskaźniki.
Tak więc, moim zdaniem, podczas gdy C ++ daje ci dużo dodatkowej liny, prawie nigdy nie trzeba jej używać do powieszenia się, a pułapek, o których mówił Joel, są banalnie łatwe do uniknięcia we współczesnym C ++.
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. Wierzę, że to kwalifikuje się jako takie pytanie ...