Bence C ++ 'ın tehlikeleri biraz abartılı.
Temel tehlike şudur: C #, unsafe
anahtar kelimeyi kullanarak "güvensiz" işaretçi işlemlerini gerçekleştirmenize izin verirken , C ++ (çoğunlukla C'nin bir üst kümesidir), istediğiniz zaman işaretçileri kullanmanıza izin verir. Bellek sızıntıları, arabellek taşmaları, sarkan işaretçiler vb.Gibi işaretleyicilerin (C ile aynı olan) kullanımındaki doğal tehlikelerin yanı sıra, C ++ bir şeyleri ciddiye almanız için yeni yollar sunar.
Tabii ki Joel Spolsky'nin bahsettiği bu "ekstra ip" temelde bir şeye iniyor: " 3 Kuralı " olarak da bilinen kendi belleklerini dahili olarak yöneten sınıflar yazmak (şimdi Kural olarak adlandırılabilir) 4 veya C ++ 11'de 5 kuralı). Bu, kendi bellek ayırmalarını dahili olarak yöneten bir sınıf yazmak istediğinizde, ne yaptığınızı bilmeniz gerekir, aksi takdirde programınız büyük olasılıkla çökecektir. Dikkatlice yanlış yapmak şaşırtıcı derecede kolay bir kurucu, kopya yapıcı, yıkıcı ve atama operatörü oluşturmanız gerekir, genellikle çalışma zamanında tuhaf çökmelere neden olur.
ANCAK , gerçek günlük C ++ programlamasında, gerçekten kendi belleğini yöneten bir sınıf yazmak çok nadirdir , bu nedenle C ++ programcılarının bu tuzaklardan kaçınmak için her zaman "dikkatli" olması gerektiğini söylemek yanıltıcıdır. Genellikle, daha çok bir şey yapıyorsunuz:
class Foo
{
public:
Foo(const std::string& s)
: m_first_name(s)
{ }
private:
std::string m_first_name;
};
Bu sınıf, Java veya C # ile yaptıklarınıza oldukça yakın görünüyor - açık bir bellek yönetimi gerektirmiyor (çünkü kütüphane sınıfı std::string
tüm bunları otomatik olarak hallediyor) ve varsayılandan bu yana hiç "3 Kural" gerektirmiyor kopya oluşturucu ve atama operatörü iyidir.
Sadece böyle bir şey yapmaya çalıştığınızda:
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;
};
Bu durumda, acemilerin atama, yıkıcı ve kopya oluşturucuyu doğru hale getirmesi zor olabilir. Ancak çoğu durumda, bunu yapmak için hiçbir neden yoktur. C ++, std::string
ve gibi kütüphane sınıflarını kullanarak zamanın% 99'unu manuel bellek yönetiminden kaçınmayı kolaylaştırır std::vector
.
İlgili başka bir sorun, belleği özel durum oluşma olasılığını hesaba katmayacak şekilde elle yönetmektir. Sevmek:
char* s = new char[100];
some_function_which_may_throw();
/* ... */
delete[] s;
Eğer some_function_which_may_throw()
gerçekte yok bir istisna için ayrılan bellek nedeniyle, bir bellek sızıntısı ile kalacaksın s
ıslah asla. Fakat yine de, pratikte bu, "3 Kuralı" nın artık gerçekten bir sorun olmadığı için aynı sebepten kaynaklanmıyor. Kendi hafızanızı ham işaretçilerle gerçekten yönetmek çok nadirdir (ve genellikle gereksizdir). Yukarıdaki problemden kaçınmak için tek yapmanız gereken bir std::string
veya kullanmaktır std::vector
ve yıkıcı istisna atıldıktan sonra yığın çözme sırasında otomatik olarak çağrılır.
Bu nedenle, genel bir tema , otomatik başlatma / imha, kopya oluşturucular ve istisnalar gibi C'den miras alınmayan birçok C ++ özelliğinin , bir programcıyı C ++ 'da manuel bellek yönetimi yaparken ekstra dikkatli olmaya zorlamasıdır. Ama yine de, bu sadece manuel bellek yönetimi yapmak istiyorsanız, standart konteynırlarınız ve akıllı işaretçileriniz olduğunda neredeyse hiç gerekmeyen bir problemdir.
Benim düşünceme göre, C ++ size fazladan bir ip verirken, kendinizi asmak için kullanmak neredeyse hiç gerekmiyor ve Joel'in bahsettiği tuzaklar modern C ++ 'da kaçınmak çok kolay.
Your questions should be reasonably scoped. If you can imagine an entire book that answers your question, you’re asking too much.
. Bunun böyle bir soru olarak nitelendirdiğine inanıyorum ...