2013-03-31 23 views
8

Verilen aşağıda sınıfı X (açıkça tanımlanmış olandan başka özel üye fonksiyonları bu deney için uygun değildir):Yeniden boyutlandırma(), kapasite aşıldığında bir vektörün içeriğinin bir hareketinden ziyade bir kopyasına neden neden oluyor?

struct X 
{ 
    X() { } 
    X(int) { } 
    X(X const&) { std::cout << "X(X const&)" << std::endl; } 
    X(X&&) { std::cout << "X(X&&)" << std::endl; } 
}; 

aşağıdaki program türü X nesnelerin bir vektör oluşturur ve kapasitesi olacak şekilde yeniden boyutlandırır t içine taşındı sınıf X bir hareket yapıcısı sağladığından

#include <iostream> 
#include <vector> 

int main() 
{ 
    std::vector<X> v(5); 
    v.resize(v.capacity() + 1); 
} 

, ben vektör önceki içerik olmasını beklediğiniz: aşıldı ve yeniden tahsis zorlanır yeniden tahsis ettikten sonra yeni depolama. Oldukça şaşırtıcı that does not seem to be the case ve ben olsun çıktısı:

X(X const&) 
X(X const&) 
X(X const&) 
X(X const&) 
X(X const&) 

Neden?

+0

Ayrıca _Microsoft_'ın bu kurala uymadığını unutmayın, bu kod _Visual C++ _ (veya _clang_ on _Windows_) ile derlenen bu kod yapıcıyı çağırır ve böylece std :: vektöründe bozuk (boş) öğeler bırakabilir Yeniden boyutlandırma hatası durumunda. – Denis

cevap

17

Paragraf (vector<> sınıf şablonu resize() üye işlevi hakkında) C++ 11 Standart belirttiği ait 23.3.6.3/14:

Açıklamalar: Bir istisna dışında başka durum oluşursa CopyInsertable T'un hareket edicisinin hiçbir etkisi yoktur. Diğer bir deyişle,

, bu (CopyInsertable olan) X için, resize()strong guarantee sunmaktadır anlamına gelir: bu başarılı veya değişmeden vektör durumunu yaprakları ya.

Bu garantiyi yerine getirebilmek için, uygulamalar copy-and-swap idiom'u kabul eder: X'un kopya kurucusu atıyorsa, orijinal vektörün içeriğini değiştirmedik, bu nedenle söz verilmiş olur. Vektörün önceki içerik olsaydı

Ancak yeni depoya taşınmak yerine kopyalanan ve hareket yapıcı o zaman geri dönülmez sahip vektör özgün içerik değişmiş olur, attı. Hareket yapıcısı atmak için değil bilinmediği sürece

nedenle

, uygulamaları önceki elementlerden taşımak güvenli olduğunu ve bu durumda, güvenli bir yeni depolama içine vektör içeriğini aktarmak için X kopyası yapıcısı kullanacak . X 'ın hareket yapıcı tanımına küçük değişiklikle

the output of the program is now the expected one, aslında, (noexcept olarak işaretleyerek):.

struct X 
{ 
    X() { } 
    X(int) { } 
    X(X const&) { std::cout << "X(X const&)" << std::endl; } 
    X(X&&) noexcept { std::cout << "X(X&&)" << std::endl; } 
//   ^^^^^^^^ 
}; 
+1

Neler oluyor - blog gönderisi sorusu? :-) –

+0

@KerrekSB: Kendime cevaplanmış soruların iyi olduğu söylendi, bunun ilginç olacağını düşündüm :) –

+0

@AndyProwl - Başka birinin bunu yapmayı denediğini gördüm ve onlar bludgeoned ... –

5

istisna teminat düşünün: yeniden tahsisat sırasında bir istisna varsa , vektörün değişmeden kalması gerekiyor. Bu, yalnızca öğelerin kopyalanması ve tüm kopya başarılı oluncaya kadar eski kümenin tutulmasıyla garanti edilebilir.

Yalnızca hareket edicinin atmadığını biliyorsanız, öğeleri yeni konuma güvenli bir şekilde taşıyabilirsiniz. Bunu başarmak için hareket ediciyi noexcept bildir.

İlgili konular