SORU
15 Temmuz 2014, Salı


Teknik olarak bu C kodu ne olur?

Sınıf vektör A içeren bir sınıf B var. Kurucu ile bu vektör başlatmak istiyorum. Sınıf A inşa edilmiştir zaman, tahrip, kopyalanan veya taşınan, böylece bazı hata ayıklama bilgisi verir.

#include <vector>
#include <iostream>

using namespace std;

class A {
public:
    A()           { cout << "A::A" << endl; }        
    ~A()          { cout << "A::~A" << endl; }               
    A(const A& t) { cout <<"A::A(A&)" << endl; }              
    A(A&& t)      { cout << "A::A(A&&)" << endl; }            
};

class B {
public:
    vector<A> va;
    B(const vector<A>& va) : va(va) {};
};

int main(void) {
    B b({ A() });
    return 0;
}

Şimdi bu programı (-fno-elide-constructors yapıcı çağrıları uzakta getirilmiştir hareket çok GCC seçeneği ile Derlenmiş) çalıştırdığımda aşağıdaki çıktıyı alıyorum:

A::A
A::A(A&&)
A::A(A&&)
A::A(A&)
A::A(A&)
A::~A
A::~A
A::~A
A::~A
A::~A

A sadece bir örnek yerine, derleyici beş örneklerini oluşturur. A iki kez taşındı ve iki kez kopyalanır. Bu kadarını da beklemiyordum. Vektör oluşturucu için başvuru tarafından geçirilen ve sınıf alanına kopyalanır. Kopyalama işlemi ya da sadece bir taşıma işlemi kurucusuna geçiyorum vektör sadece bir rvalue olduğunu umuyordum çünkü) bir tek, iki nüsha ve iki hamle değil beklerdim. Birisi tam olarak ne bu kod bana açıklayabilir mi lütfen? Nereye ve neden A tüm bu kopyalar oluşturmak mı?

CEVAP
15 Temmuz 2014, Salı


Tersten yapıcı çağrıları üzerinden gitmek yararlı olabilir.

B b({ A() });

** 16, derleyici oluşturmak için const vector<A>& alır B kurucusunu çağırmak gerekir. Bu oluşturucu vektör, öğeleri dahil olmak üzere bir kopyasını yapmak gerekir. Bakın çağrı decimal ikinci kopyası.

B'nin kurucu, derleyici std::vector initializer_list kurucu çağırmak gerekir. geçirilecek geçici vektör oluşturmak için Bu yapıcı da, initializer_list bulunan bir kopyasını yapmak gerekir*. Bakın çağrı yapıcı bir kopyası.

Standart initializer_list nesneler §8.5.4 [malzeme.nasıl oluşturulduğunu belirtir ınit.liste]/p5:

23 ** türünde bir nesne inşa edilmiştir Eğer uygulama N bir dizi ayrılmış gibi başlatıcı listesi yazın unsurları 24****N öğe sayısı olduğu , başlatıcı listesi. Bu dizinin her öğesi-kopya ile başlatıldı. başlatıcı listesinde karşılık gelen element ve 25* *nesne bir dizi ifade etmek için inşa edilmiştir.

Aynı türden bir şey bir nesneyi kopyala-başlatma aşırı yük çözüm oluşturucu kullanmak için seçmek için kullanır (§8.5 [malzeme.başlangıç]/bkz s17), aynı türden bir rvalue ile eğer varsa hareket oluşturucu çağırmak olacaktır. Böylece, inşa et initializer_list<A> hazırladı başlatıcı listesi, derleyici ilk inşa bir dizi, bir const A ile hareket geçici A inşa A(), neden bir hareket kurucusunu çağırmak, ve sonra oluşturmak initializer_list nesnesine başvurmak için bu dizi.

G diğer hareket, ama nereden geldiğini çözemedim. initializer_lists genellikle işaretçiler ve kopyalama bir temel öğeleri kopyalamak değil bu standart zorunlu bir çift başka bir şey daha vardır. g geçici initializer_list oluştururken 55* *gibi görünüyor. Hatta bir lvalue initializer_list oluştururken 56**.

En iyi tahminim tam anlamıyla standart olmayan normatif örnek uygulama. Bu standart aşağıdaki örnek sağlar:

struct X {
    X(std::initializer_list<double> v);
};

X x{ 1,2,3 };

Başlatma bir şekilde kabaca uygulanacak bu:**

const double __a[3] = {double{1}, double{2}, double{3}};
X x(std::initializer_list<double>(__a, __a 3));

uygulama bir initializer_list kurabileceği varsayımıyla işaretçiler bir çift oluşturur.

Eğer bu örnek tam anlamıyla alırsanız, bu dizi bizim durumumuzda initializer_list temel olarak inşa edilecektir:

const A __a[1] = { A{A()} };

hangi yapar tabi iki hareket oluşturucu çağırır, çünkü bu yapılar bir geçici A kopyala-başlatır bir ikinci geçici A birincisi, sonra Kopyala-başlatır bir dizi üye ikinci geçici. Standart normatif metin, ancak, sadece bu bir hata gibi görünüyor bu yüzden bir kopya başlatma, iki değil, olması gerektiğini açıkça ortaya koyuyor.

Son olarak, ilk A::A doğrudan A() geliyor.

Çok yıkıcı çağrıları hakkında tartışmak için var. Tüm geçici (bağımsız olarak) oluşturulan sırasında inşaat b olacak tahrip sonunda açıklamada tersten inşaat ve A saklı b olacak tahrip b söner kapsamı.


*Standart kütüphane kaplar initializer_list kurucular kurucu list.begin() list.end() ile iki yineleyicisi alarak yürütmesini eşdeğer olarak tanımlanır. Bu üye işlev bir hareket olamaz, 49**, dönüş. C 14, yedekleme bir dizi makineden hareket veya başka bir şekilde bunu değiştiremezsin o daha çok const, yapılır.

**Bu cevap aslında alıntı N3337 (C 11 standart artı bazı küçük değişiklikler yayın) dizisi olan elementlerin türü E yerine const E ve dizideki örnek tipi double. C 14, temel dizi CWG 1418 sonucunda const yapıldı.

Bunu Paylaş:
  • Google+
  • E-Posta
Etiketler:

YORUMLAR

SPONSOR VİDEO

Rastgele Yazarlar

  • bcbauer

    bcbauer

    7 ŞUBAT 2007
  • fast2hell

    fast2hell

    16 AĞUSTOS 2006
  • Willie D.

    Willie D.

    16 Aralık 2006