Yükleniyor...

C++ vector Kullanımı ve Özellikleri

C++ std::vector kullanımını öğrenin. Dinamik diziler, eleman ekleme, silme ve erişim işlemlerini pratik örneklerle keşfedin.

std::vector, C++’ta en yaygın kullanılan sıralı kapsayıcıdır. Ardışıl (contiguous) bellekte dinamik dizi sağlar: rastgele erişim O(1), sona ekleme amortize O(1), araya ekleme/silme ise eleman kaydırmaları nedeniyle genellikle O(n) maliyete sahiptir. Bu yazıda kapasite yönetimi (size/capacity), büyüme stratejisi, reserve/resize, push_back vs emplace_back, iteratör geçerliliği, bellek düzeni (data()), shrink_to_fit ve performans ipuçlarını ele alacağız.


1) Temel Kullanım


#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v;              // boş
    v.push_back(10);
    v.push_back(20);
    v.push_back(30);

    cout << "size=" << v.size() << " capacity=" << v.capacity() << "\n";
    cout << v[1] << " " << v.at(2) << "\n"; // [] sınır kontrolsüz, at() kontrollü

    for (int x : v) cout << x << " ";
}

size eleman sayısını, capacity ise yeniden ayırma (reallocation) gerekmeksizin saklanabilecek maksimum eleman sayısını gösterir.


2) Contiguous Bellek ve data()

vector elemanları bitişik (contiguous) bellektedir; C API’lerine ham işaretçi ile geçilebilir.


#include <cstring>  // memcpy
#include <vector>

int main() {
    vector<char> buf(8, 0);
    const char* msg = "C++";
    memcpy(buf.data(), msg, 3); // güvenli: contiguous depolama
}

Bitişik bellek garantisi, SIMD/IO ve kütüphane entegrasyonları için avantajdır (ör. grafik, ses, ağ paketleri).


3) Büyüme Stratejisi, reserve ve resize


#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v;
    v.reserve(1000);        // reallocation sayısını düşürür
    for (int i=0;i<1000;i++) v.push_back(i);

    v.resize(1200, -1);     // 200 yeni eleman: -1 ile doldur
    cout << v.size() << " " << v.capacity() << "\n";
}

Büyüme faktörü uygulama/derleyiciye göre değişir (tipik olarak ~1.5–2x). Büyük toplu eklemelerde reserve ciddi hız kazandırır.


4) Ekleme ve Silme: push_back vs emplace_back, insert/erase


#include <string>
#include <vector>
using namespace std;

struct Book { string title; double price; int pages;
    Book(string t, double p, int s): title(t), price(p), pages(s) {}
};

int main() {
    vector<Book> books;
    books.emplace_back("C++ Primer", 180.0, 950); // ctor doğrudan çağrılır
    books.push_back(Book{"Effective C++", 150.0, 320}); // geçici + move
    books.insert(books.begin(), {"Clean Code", 175.0, 464}); // başa ekleme

    books.erase(books.begin()+1); // aradan silme
}

Yerinde kurulum (emplace) özellikle kopyalanması maliyetli tiplerde avantaj sağlar. Araya sık ekleme/silme gerekiyorsa deque veya list düşünün.


5) İteratör Geçerliliği (Iterator Invalidation)

Yeniden ayırma (reallocation) veya eleman kaydırmaları, iteratörleri ve işaretçileri geçersiz kılar.


#include <vector>
#include <iostream>
using namespace std;

int main() {
    vector<int> v{1,2,3};
    auto it = v.begin();
    v.push_back(4); // kapasite yetmezse reallocate olabilir
    // it artık geçersiz olabilir; kullanmak UB olur
}

Çözüm: Kritik bölümlerde reserve kullanın; reallocation sonrası iteratörleri yeniden alın.


6) Performans İpuçları


7) assign, swap, shrink_to_fit


#include <vector>
using namespace std;

int main() {
    vector<int> v{1,2,3,4,5};
    v.assign(3, 9);              // {9,9,9}
    vector<int>(v).swap(v);      // shrink idiomu: kapasiteyi küçültmek için
    v.shrink_to_fit();           // talep (kesin değil)
}

vector<T>(v).swap(v) sık kullanılan “shrink idiomu”dur; geçici ile takas sonrası kapasite genellikle boyuta eşitlenir.


8) Sıralama, Arama ve Algoritmalar


#include <vector>
#include <algorithm>
#include <iostream>
using namespace std;

int main() {
    vector<int> a{5,1,4,2,3};
    sort(a.begin(), a.end());                     // 1 2 3 4 5
    bool has4 = binary_search(a.begin(), a.end(), 4);
    auto pos = lower_bound(a.begin(), a.end(), 3); // ilk >= 3 konum
    cout << has4 << " @" << (pos - a.begin()) << "\n";
}

std::ranges (C++20) ile daha okunaklı boru hattı (pipeline) tarzı kullanım mümkündür.


9) İleri Konular: Allocatör, Boolean Vektör, Küçük Nesneler


10) Örnek: Kayıt Listesi (Book)


#include <vector>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

struct Book {
    string title; double price; int pages;
    Book(string t,double p,int s): title(move(t)), price(p), pages(s) {}
};

int main() {
    vector<Book> books;
    books.reserve(4);
    books.emplace_back("C++ Primer", 180.0, 950);
    books.emplace_back("Effective C++", 150.0, 320);
    books.emplace_back("Clean Code", 175.0, 464);

    // Fiyata göre artan sırala
    sort(books.begin(), books.end(),
         [](const Book& a, const Book& b){ return a.price < b.price; });

    // 160+ fiyatlı ilk kitabı bul
    auto it = find_if(books.begin(), books.end(),
        [](const Book& b){ return b.price >= 160.0; });

    if (it != books.end())
        cout << it->title << " " << it->price << "\n";
}

11) Sık Yapılan Hatalar


12) TL;DR

  • vector = contiguous, rastgele erişim O(1), sona ekleme amortize O(1).
  • reserve reallocation sayısını azaltır; resize boyutu değiştirir.
  • emplace_back yerinde kurar; pahalı kopyalardan kaçınır.
  • Reallocation/insert/erase iteratörleri geçersiz kılabilir.
  • data() ile C API’lerine köprü kurabilir, IO/SIMD için avantaj sağlayabilirsiniz.
  • shrink_to_fit talep niteliğindedir; “swap ile shrink” daha etkili olabilir.
  • Araya sık operasyon gerekiyorsa deque/list düşünün.
  • Tüm örnekler Visual Studio 2022 ve GCC 11+ ile uyumludur.

İlişkili Makaleler