Evet dostlar, C++ kabiliyetlerinden kalan bir iki tanesine bakmaya devam ediyoruz. Bu yazımda, hızlıca ve kısaca bu kabiliyete bakıp, kalan diğer C++ 11 kabiliyetlerine bakmaya devam edeceğiz. Bildiğiniz üzere bir kaç hafta önce C++ 20 standardı da kabul edildi. Yani daha, öğrenecek çok konu var.
std::array
std::array‘i kısaca, C dizilerini herhangi bir ekstra masraf getirmeden C++ konteynerleri gibi kullanmanıza olanak sağlayan sınıftır. Bir diğer ifade ile bu sınıfı kullanmanız ile geleneksel dizileri kullanmanız arasında performans anlamında hiç bir fark bulunmamaktadır. Aslına bakarsanız, gerçekleme anlamında da aşağıdakine çok benzer bir şekilde “wrap” edilerek tanımlanabilir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
template<typename T, size_t N> class array { public: // Veri T _data[N]; // Indeks operatoru (l-value) T& operator[](size_t); // Indek operatoru (r-value) const T& operator[](size_t) const; ... }; |
std::array‘i kullanabilmek için <array> başlık dosyasını eklemeniz yeterli. std::array ile deklerasyon yaparken, ilgili dizinin içeriğinin tipini ve boyutunu vermelisiniz. Bu boyut daha sonra değiştirilememekte.
Kullanımı normal dizilere benzese de, aşağıdaki güzellikleri de kullanmanıza olanak sağlar 😉
En önemli özelliklerden birisi, fonksiyonlara parametre olarak, kopyalanarak geçirilebilir ve dönülebilir. Normal dizilerde varsayılan olarak işaretçi olarak geçirilerek, dönülmekteydi. Yani fonksiyon içerisinde yapılan değişikliklerden diziler etkilenmektedir. Hemen bir örnek ile bakalım:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
#include <iostream> #include <cstdint> #include <array> #include <memory> using namespace std; void passingArrays(int32_t intTraditionalArray[5], array<int32_t, 5> intNewArray) { for (int32_t i = 0; i < 5; ++i) { intTraditionalArray[i] = i; intNewArray[i] = i; } } int main() { int32_t traditionalArray[5] = {}; array<int32_t, 5>newArrayA = {}; // Ornek fonksiyona gecirilme // Burada std::array `pass by value` olarak gecirilmekte // Geleneksel diziler `pass by reference` olarak gecirilmekte passingArrays(traditionalArray, newArrayA); cout << "Geleneksel Dizi Icerigi: "; for (int32_t i = 0; i < 5; ++i){ cout << traditionalArray[i] << " "; } cout << "\nYeni Dizi Icerigi: "; for (int32_t i = 0; i < 5; ++i){ cout << newArrayA[i] << " "; } return 0; } |
Sunulan API’ler, STL tarafından sunulan diğer API’ler ile daha uyumlu ve konteynerlere benzemektedir. (Burada, şunu da eklemekte fayda var, artık geleneksel diziler de bir takım STL kabiliyetleri ile kullanılabilmektedir). Bu bağlamda array’ler ile iterator kullanılabilmektedir:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <iostream> #include <array> using namespace std; int main() { array<int32_t, 5> intArray{{1,2,3,4,5}}; cout << "Dizideki elemanlar: \n"; for(auto elem: intArray){ cout << elem << " "; } cout << "\n"; // Iterator kullanarak dolasalim auto itr = aInt.begin(); while(itr != aInt.end()) { cout << *itr << " "; itr++; }; cout << "\n"; return 0; } |
Çok boyutlu dizileri, aşağıdaki örnektekine benzer şekilde oluşturabilirsiniz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
#include <iostream> #include <array> using namespace std; int main() { // 3x3 lik matrix array<array<int32_t, 3>, 3> int2DArray{{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }}; cout << "Dizideki elemanlar: \n"; for(auto& row: int2DArray) { for(auto element: row) { cout << element << " "; } cout << "\n"; } return 0; } |
Yukarıdaki tanımlama uzun derseniz, yine daha önce işlediğimiz “using” ile “type alias” yaparak daha kısaltıp genelleştirebiliriz:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
#include <iostream> #include <array> using namespace std; // Yukaridaki tanimlama uzun derseniz asagidaki gibi bir kullanim da mumkun ;) template<typename type, int32_t size> using Matrix = array<array<type, size>, size>; int main() { Matrix<int32_t, 3> intMatrix{{ {1, 2, 3}, {4, 5, 6}, {7, 8, 9} }}; cout << "Dizideki elemanlar: \n"; for(auto& row: intMatrix) { for(auto element: row) { cout << element << " "; } cout << "\n"; } return 0; } |
Geleneksel dizilerdeki gibi [] operatörü kullanılabileceği gibi, at(), front(), back() gibi API’ler de sunulmaktadır. Boyut bilgisini, size() fonksiyonu ile sorgulayabilirsiniz. Benzer şekilde, ilgili dizinin boş olup/olmadığı da empty() API’si de kullanılabilir. Yukarıdaki örneklerde kullanılan initializer_list desteği.
İşaretçilere otomatik ya da “implicit” olarak dönüştürülmemekte. Bunu aslında bir önlem olarak da düşünmekte fayda var. Normal diziler, yukarıda da bahsedildiği üzere, işaretçi olarak geçirilmektedir. Peki, std::array içeriğine bu şekilde ulaşmak istediğiniz durumda ne kullanacaksınız. Bu amaçla data() API’si sunulmakta, bu sayede işaretçiler kullanılarak içeriğe ulaşılabilir ve güncellenebilir. Yine yukarıdaki örneklere benzer bir örnek ile bu API’ye göz atalım:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
#include <iostream> #include <array> #include <cstring> // memset icin using namespace std; void printArray(const array<int32_t, 5>& input) { cout << "Dizi icerigi: \n"; for(auto elem: input){ cout << elem << " "; } cout << "\n"; } int main() { array<int32_t, 5> intArray{{1,2,3,4,5}}; // Ilk icerik printArray(intArray); // Simdi butun diziyi sifirlayalim memset(intArray.data(), 0, sizeof(int32_t) * 5); printArray(intArray); // Dolduralim intArray.fill(5); printArray(intArray); // Simdi isaretci marifeti ile dolduralim int32_t* intPtr(intArray.data()); for(int32_t i = 0; i < 5; ++i){ intPtr[i] = i; } printArray(intArray); return 0; } |
Bu noktada aklınıza geleneksel diziler, std::array ve std::vector’leri hangi durumlarda kullanmalıyım diye bir sour gelebilir. Öncelikli olarak, eğer derleme zamanında, kullanacağınız dizinin boyutu belli ise ve boyutunun değişmesi öngörülmüyorsa, std::array doğru bir seçim olacaktır. Aksi durumda, yine ihtiyaç duyulan isterlere göre std::vector daha uygun olabilir. Mümkün olduğunca geleneksel diziler yerine std::array tercih edilebilir.
Evet yazılımperver dostlar, uzun bir aradan sonra bir C++ yazımızı daha tamamladık, bir sonraki yazıma kadar kendinize çok iyi davranın ve sağlıkla kalın.