bir vektörü diğerine kopyalamanın hızlı yolu


155

İki yolu tercih ederim:

void copyVecFast(const vec<int>& original)
{
  vector<int> newVec;
  newVec.reserve(original.size());
  copy(original.begin(),original.end(),back_inserter(newVec));
}

void copyVecFast(vec<int>& original)
{

  vector<int> newVec;
  newVec.swap(original); 
}

Bunu nasıl yapıyorsun?


14
İkincisi yanıltıcı bir isme sahiptir - bir kopya olmadığı için (hızlı olmasına rağmen).
İsimsiz

Yanıtlar:


125

Bağımsız değişkeni başvuru ile gönderirseniz ikinci örneğiniz çalışmaz. Demek istediğin

void copyVecFast(vec<int> original) // no reference
{

  vector<int> new_;
  new_.swap(original); 
}

Bu işe yarardı, ancak daha kolay bir yol

vector<int> new_(original);

Güzel, işe yarıyor. Fakat bu bir dizi vektör için çalışmaz: örneğin: vector <int> A [n];
ABcDexter

8
Bu takas, kopya değil.
sdd

1
@sdd - hayır değil. Argüman listesini kontrol edin. original, işlev bağımsız değişkeninin bir kopyasıdır.
rlbond

@rlbond Yanlışlıkla cevabı indirdi :(, Lütfen yazıyı düzenleyebilir misiniz, böylece aşağı oyu kaldırabilir ve yukarı oy verebilir miyim?
Shubham Sharma

250

Yine de aynı değiller, değil mi? Biri bir kopya, diğeri bir takas . Dolayısıyla işlev adları.

Benim favorim:

a = b;

Vektörler nerede ave bnelerdir.


3
Aslında yaklaşım değere göre geçiyor, derleyici kopyalama yapıcısını çağırıyor ve yeni oluşturulan öğeyi değiştiriyor. Bu yüzden rlbond, aynı etkiyi elde etmek için kopya kurucusunu doğrudan çağırmayı önerir.
David Rodríguez - dribeas

1
Ancak, orijinali val olarak ileten bir işlev olmadan rlbon'u çağıramazsınız. Aksi takdirde, orijinali boşaltır. İkinci çözüm, her zaman değere göre aramanızı ve böylece orijinal vektördeki tarihi kaybetmemenizi sağladı. (İşaretçilerle takas anlaşmaları varsayarsak)
Eyad Ebrahim

Bu, b öğelerini a'ya taşımayacak mı (b = size == 0 ile)?
Jonathan.

1
@Jonathan. Diyelim ki o a = bzaman hayır. Atama şu anlama gelir: değişmeden aeşit olun . Buna karşılık, içeriklerini alışverişinde (böylece 'ın artık ne olacağını daha önce olmuştu s'). Belki de bir taşıma işlemi düşünüyorsunuz (C ++ 11'de olduğu gibi, ancak bunun gibi sıradan bir ödevde değil). Böyle bir hareket ahem, "ilginç" bir durumda bbstd::swap(a, b)bsizeab
kalır

1
@Jonathan. Çift ve işareti not edin &&. Bu sürüm yalnızca bir rvalue referansı için kullanılacaktır. Sabit olmayan herhangi bir değerle eşleşmez ( byukarıdaki örneğimde olduğu gibi). Daha da fazla karmaşıklık düzeyi için bkz. En.cppreference.com/w/cpp/language/value_categoryb diyerek birine dönüşebilirsiniz . a = std::move(b);
Daniel Earwicker

74

Bu, bir vektörün kopyasını almanın başka bir geçerli yoludur, sadece yapıcısını kullanın:

std::vector<int> newvector(oldvector);

Bu, std::copytüm vektörü baştan sona std::back_insertyeni vektörün içine yürümek için kullanmaktan daha kolaydır .

Bununla birlikte, .swap()bir kopya değil, iki vektörü değiştirir. Orijinali, artık hiçbir şey içermeyecek şekilde değiştirirsiniz! Bu bir kopya değil.


Benim için daha esnek a = b;çünkü zaten üye ab
alanım

20

Doğrudan cevap:

  • Bir =operatör kullanın

Bir vektörden diğerine değerler atamak std::vector::operator=için kabın genel üye işlevini kullanabiliriz std::vector.

  • Yapıcı işlevi kullanma

Ayrıca, bir yapıcı işlevi de mantıklıdır. Parametre (ör. x) Olarak başka bir vektör içeren yapıcı işlevi , öğelerin her birinin kopyasını xaynı sırayla içeren bir kap oluşturur .

Dikkat:

  • Kullanmayın std::vector::swap

std::vector::swapdeğil kopyalama başka bir vektör, aslında Adından da anlaşılacağı gibi, iki vektörün elemanları takas edilir. Başka bir deyişle, kopyalanacak kaynak vektör sonra değiştirilir std::vector::swap, muhtemelen beklediğiniz gibi değildir.

  • Derin mi sığ mı?

Kaynak vektördeki elemanlar diğer verilere işaret ederse, bazen derin bir kopya istenir.

Vikipedi göre:

Derin bir kopya, yani alanların kaydı kaldırılmıştır: kopyalanan nesnelere başvurular yerine, başvurulan nesneler için yeni kopya nesneleri ve B'ye yerleştirilen bu nesnelere başvurular.

Aslında, şu anda C ++ 'da derin bir kopya yapmak için yerleşik bir yol yoktur. Yukarıda belirtilen tüm yollar sığdır. Derin bir kopya gerekiyorsa, bir vektörde gezinebilir ve referansları manuel olarak kopyalayabilirsiniz. Alternatif olarak, çaprazlama için bir yineleyici düşünülebilir. Yineleyici tartışma bu sorunun ötesindedir.

Referanslar

std::vectorCplusplus.com sayfasının sayfası


14

vektörleri kopyalamak için takas kullanmamalısınız, "orijinal" vektörü değiştirir.

orijinali parametre olarak yenisine geçirin.


14
new_vector.assign(old_vector.begin(),old_vector.end()); // Method 1
new_vector = old_vector; // Method 2

-14

ALREADY vektörü mevcutsa ve sadece kopyalamak istiyorsanız, bunu yapabilirsiniz:

newVec.resize(oldVec.size());
memcpy(&newVec.at(0), &oldVec.at(0), oldVec.size());

1
Lütfen memcpy yapma. Memcpy boyutu bayt olarak aldığından bu da işe yaramaz. Ayrıca diğer vektör zaten varsa newVec = oldVec, diğer cevaplardan biri ile aynı olanı yapabilirsiniz.
FDinoff

Evet haklısın. Bunu görmedim. @FDinoff, biri aşağıda çalışmasına rağmen neden memcpy kullanmamanızı öneriyorsunuz? NewVec = oldVec'den çok daha hızlı görünüyor. memcpy (& newVec.at (0), & oldVec.at (0), oldVec.size () * sizeof (int));
sgowd

1
Genel durumda, bir nesneyi kopyalama yapıcısını çağırmadan kopyalamak ince hatalara yol açabilir. Bu durumda aynı performansa sahip olacaklarını düşünürdüm. Eğer olmasaydı, vektörün performansı optimize etmediğini söyleyebilirim, çünkü bunu zaten yapıyor olmalı. Aslında bir karşılaştırma ölçütü yazdınız mı?
FDinoff

Sizi eleştirmiyordum .. Takım liderim de aynı şeyi önerdi ve anlamaya çalışıyordum.
sgowd

(Beni eleştirdiğini sanmıyordum.) Hala anlamadığın bir şey var mı?
FDinoff
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.