Diziler C ++ 'da kullanılmalı mı?


97

O zamandan beri std::listve std::vectorvar, C ++ 'da geleneksel C dizilerini kullanmak için bir neden var mı, yoksa aynen olduğu gibi kaçınılmalı mallocmı?



18
@Als: Bu soru, iki özel kap arasındaki farkla ilgili iken, bu soru genel olarak ham diziler ve standart kaplar arasındaki farkla ilgilidir.
Jon Purdy

Yanıtlar:


109

Kullanılabildiği C ++ 11'de std::arrayyanıt "evet, dizilerden kaçınılmalıdır". C ++ 11'den önce, dizileri otomatik depolamada (yani yığın üzerinde) tahsis etmek için C dizilerini kullanmanız gerekebilir.


3
ancak birçok derleyici hala C ++ 11 desteğinden yoksundur. Std :: array eksikliği göz önüne alındığında, birini diğerinden daha iyi kullanmanın ne zaman daha iyi olacağına karar
vermelisiniz

4
std :: array, büyük projeleri derleme süresi ve muhtemelen kod boyutu açısından etkileyen bir şablondur çünkü her T, N kombinasyonu için şablon yeniden başlatılır.
zvrba

std :: vector, standart olarak veri hizalamasını garanti eder, böylece neredeyse her yerde kullanılabilir. C ++ 11 ile C dizilerini kullanmak için gerçekten bir neden yoktur.
Nils

16
@Nils dizileri de hizalamayı garanti eder. Ayrıca, otomatik depolama tahsisi ("yığın"), dinamik depolama tahsisinden çok daha hızlıdır. Ben ise biliyorum ben tam olarak kullanılması vektörü için hiçbir neden yok, 3 elemanlarını [Bir üçgenin örneğin, koordinatlar].
zvrba

9
@zvrba - std :: array ve C dizilerini kullanırken oluşturulan derlemeyi kontrol edin. Hiç fark yok.
Nemanja Trifunovic

85

Kesinlikle, std::arrayC ++ 11'de olmasına rağmen , pratik olarak sadece statik veriler için. C tarzı dizilerin üç önemli avantajı vardır std::vector:

  • Dinamik ayırma gerektirmezler. Bu nedenle, çok sayıda çok küçük diziye sahip olabileceğiniz yerlerde C tarzı diziler tercih edilmelidir. N boyutlu nokta gibi bir şey söyleyin:

    template <typename T, int dims>
    class Point
    {
        T myData[dims];
    // ...
    };
    

    Tipik olarak, dimsçok küçük (2 veya 3), Tyerleşik bir tür ( double) ve std::vector<Point>milyonlarca öğeyle sonuçlanabileceğiniz bir hayal edilebilir . Kesinlikle 3 çiftli milyonlarca dinamik ayırma istemezsiniz.

  • Statik başlatma desteği. Bu yalnızca aşağıdaki gibi bir şeyin olduğu statik veriler için bir sorundur:

    struct Data { int i; char const* s; };
    Data const ourData[] =
    {
        { 1, "one" },
        { 2, "two" },
        //  ...
    };
    

    Bu, tüm başlatma sorunlarını std::stringortadan kaldırdığı için genellikle bir vektör (ve ) kullanmaya tercih edilir ; herhangi bir gerçek kod çalıştırılmadan önce veriler önceden yüklenir.

  • Son olarak, yukarıdakilerle ilgili olarak, derleyici, başlatıcılardan dizinin gerçek boyutunu hesaplayabilir. Bunları saymanıza gerek yok.

C ++ 11'e erişiminiz varsa std::array, ilk iki sorunu çözer ve kesinlikle ilk durumda C tarzı diziler yerine kullanılmalıdır. Bununla birlikte, üçüncüyü ele almaz ve derleyici boyutunun başlatıcı sayısına göre diziye sahip olması, yine de C tarzı dizileri tercih etmek için geçerli bir nedendir.


11
C tarzı dizi başlatma aynı zamanda kendinizi tekrar etme ihtiyacını da ortadan kaldırır. int i[] = { 1, 2, 3 };ile çalışmaya devam ediyor int i[] = { 1, 2, 3, 4 };. array<int, 3>olarak manuel olarak değiştirilmesi gerekiyor array<int, 4>.

10
@JoeWreschnig Kolayca unutabileceğiniz bir değişiklik. Bir öğe eklerseniz, derleyici şikayet etmelidir, ancak birini kaldırırsanız, sonunda fazladan, 0 başlatılmış bir öğe elde edersiniz. Hala bu tür statik veriler için yoğun olarak C stili dizileri kullanıyorum.
James Kanze

3
İlk cümle mantıklı değil.
Konrad Rudolph

4
Üçüncü nokta kullanılarak yerine zarif çözülebilir make_arrayfonksiyonu benzer make_pairvb Şapka-ucu @R. Martinho Fernandes .
Konrad Rudolph

@KonradRudolph: Elbette öyle. Andreas, "Diziler C ++ 'da kullanılmalı mı?" Diye soruyor, James buna "Kesinlikle, ancak std::arrayC ++ 11'de olmasına rağmen, pratik olarak yalnızca statik veriler için [kullanılmalıdır]".
Jon Purdy

15

Asla "asla" deme, ancak rollerinin STL'nin gerçek veri yapıları tarafından büyük ölçüde azaldığını kabul ediyorum.

Nesnelerin içindeki kapsüllemenin bu gibi seçimlerin etkisini en aza indirmesi gerektiğini de söyleyebilirim. Dizi bir özel veri üyesiyse, sınıfınızın istemcilerini etkilemeden diziyi içeri veya dışarı takas edebilirsiniz.


11

Dinamik bellek ayırmayı kullanamadığınız güvenlik açısından kritik sistemler üzerinde çalıştım. Hafıza her zaman yığında olmalıdır. Bu nedenle, bu durumda, boyut derleme zamanında sabit olduğundan dizileri kullanırsınız.


8
C ++ 11'den önce kabul ederdim, ancak std::array<T>yığınlara ayırır ve temelde ham dizide ek yük yoktur.
111111

5
@ 111111 - Kabul edildi. Ancak bu sektördeki bazı kişilerin henüz C ++ 11'e geçmediğini biliyorum
Ed Heal

Bu yüzden size olumsuz oy vermediğimi biliyorum, ancak bence boost'un bir versiyonu vardı ve kendi versiyonunuzu da almak kolay.
111111

6
ancak güvenlik açısından kritik sistemlerde, yeni derleyici özellikleri (daha az test edilmiş) kullanmazsınız ve boost kullanmazsınız.
James Kanze

3
Güvenlik açısından kritik birçok sistem, daha yeni derleyici özelliklerine bile sahip olmayan ESKİ derleyiciler üzerine inşa edilmiştir çünkü araç zincirlerini değiştirmek, tonlarca evrak, test ve sertifika gerektiren yavaş, pahalı bir süreçtir.
Brian McFarland

6

arrayiçinde c++sen dinamiğinin hızlı alternatif Sabit ölçülere verir büyüklükte std::vectorve std::list. std :: array , içindeki eklemelerden biridir c++11. Std kapsayıcılarının yararını sağlarken, yine de C tarzı dizilerin toplu tür anlambilimini sağlar.

Bu yüzden , gerektiği yerde c++11kesinlikle std::arrayvektör üzerinden kullanırdım. Ama C tarzı diziden kaçınırdım C++03.


4

Çoğu zaman, hayır , mesela ham dizileri kullanmak için bir neden düşünemiyorum vectors. Kod yeniyse .

Kitaplıklarınızın diziler ve ham işaretçiler bekleyen kodlarla uyumlu olması gerekiyorsa dizileri kullanmaya başvurmanız gerekebilir.


1
... ama C ++ 03'ten beri bir vektör, okumak veya yazmak için işaretçi ile erişebileceğiniz bir diziye "aslında" sahiptir. Bu, dizilere işaretçiler bekleyen çoğu kod durumunu kapsar. Sadece kod diziyi ayırdığında veya serbest bıraktığında bir vektör kullanamazsınız.
Steve Jessop

@SteveJessop dahili diziye erişebilir misiniz?
Luchian Grigore

1
@LuchianGrigore: vector.data()C ++ 11 veya &vector.front()öncesinde.
Mike Seymour

@Luchian: vektör boş değilse, bir öğeye bir işaretçi götürebilirsiniz (ve eğer boşsa, bir boş işaretçi ve 0 uzunluğunu herhangi bir mantıklı yazılmış fonksiyona geçirebilirsiniz. sıfır boyutlu arabellek). C ++ 03'te eklenen vektör yakınlık garantisinin hemen hemen tek amacı, vektörlerin işaretçi yönelimli kod tarafından tampon olarak kullanılmasına izin vermekti.
Steve Jessop

1
@SteveJessop Ve birçok insanın zaten garantili olduğunu düşünmesi ve onları hayal kırıklığına uğratmamak tercih edildi.
James Kanze

4

Bir çok insanın yığındaki dizileri ayırmak için std :: array'i ve yığın için std :: vector'u işaret ettiğini biliyorum. Ancak hiçbiri yerel olmayan uyumu desteklemiyor gibi görünüyor. SSE veya VPX talimatlarını kullanmak istediğiniz herhangi bir tür sayısal kod yapıyorsanız (dolayısıyla sırasıyla 128 veya 256 bayt hizalama gerektirir), C dizileri yine de en iyi seçeneğiniz gibi görünecektir.


3

Dizilerin hala yararlı olduğunu söyleyebilirim, eğer az miktarda statik veri depoluyorsanız neden olmasın.


2

Üzerinde (otomatik olarak serbest bırakılmasına zaman ihtiyaç yönetecek ders şeye sarılmış arasında) bir dizinin tek avantajı std::vectortek düşündüğüm yani vector, onun verilerin sahipliğini geçemez sizin derleyici desteklerin sürece C ++ 11 ve hareket kurucular.


6
"vektör, verilerinin sahipliğini aktaramaz" - evet, C ++ 03'te kullanabilir swap.
Steve Jessop

2

C tarzı diziler temel bir veri yapısıdır, bu nedenle onu kullanmanın daha iyi olduğu durumlar olacaktır. Ancak genel durum için, temeldeki verilerin köşelerini yuvarlayan daha gelişmiş veri yapılarını kullanın. C ++, çoğu basit dizilerle çalışan bellekle çok ilginç ve yararlı şeyler yapmanızı sağlar.


3
C tarzı diziler std::arrays'den nasıl daha temeldir? Her ikisi de birçok durumda aynı derlemede derlenecektir.
35'te sol

1
Daha temel olması daha temeldir. Bir dizinin ne yapacağını biliyorsunuz, std :: array, standart kitaplığa bağlı olduğu için uygulama tuhaflıklarına sahip olabilir.
James Wynn

1
@JamesWynn Pek değil. std::arraystatik dizilerin üzerine inşa edilmiş kesin olarak tanımlanmış semantiğe sahiptir.
Konrad Rudolph

1

STL kaplarını dahili olarak kullanmalısınız, ancak işaretçileri farklı modüller arasında bu tür kaplara geçirmemelisiniz, yoksa bağımlılık cehennemine girersiniz. Misal:

std::string foo;
//  fill foo with stuff
myExternalOutputProc(foo.c_str());

çok iyi bir çözüm ama değil

std::string foo;
//  fill foo with stuff
myExternalOutputProc(&foo);

Bunun nedeni, std :: string'in birçok farklı yolla gerçeklenebilmesidir, ancak c-style string her zaman c-style string'tir.


Söylemeye çalıştığınız şey şu: Standart kitaplığın farklı derleyicileri / uygulamaları bunları oluşturmak için kullanılmışsa, farklı nesne kodunu birbirine bağlamayın. Bu kesinlikle doğru. Bunun orijinal soruyla nasıl bir ilişkisi var?
jogojapan

Dizilerin veya STL kaplarının ne zaman kullanılacağı sadece bir tavsiye . Bir kap kullanarak veri oluşturun, bir dizi olarak aktarın. Dizeler oluşturan diğer veriler için myExternalOutputProc (foo.rawPointerGet (), foo.count ()) gibi bir şeye sahip olursunuz;
user877329

Ancak bu sorunlar yalnızca standart kitaplığın farklı uygulamalarını aynı projede birleştirdiğinizde ortaya çıkar. Çılgınca. Herhangi bir normal kod parçasında, diyelim ki bir vektörü referans olarak (veya C ++ 11'de taşımak) bir işleve geçirmek tamamen uygundur.
jogojapan

1
Eklentileri
beğendim
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.