2013-07-03 12 views
5

Nie mogę zrozumieć, dlaczego w następnym kawałku kodu, zdefiniowany kopia constuctor nie drukuje ...C++ Kopiuj Konstruktor Oddity

#include <iostream> 
using namespace std; 
class B { 
    static int count; 
    int data; 
    int id; 

    void print(const char* p) 
    { 
     cout <<p <<", "<<id <<", " << data << endl; 
    } 

    public: 

    B(int d=0) 
    { 
     data=d; id=++count; print("B(int)"); 
    } 
    B(const B& a) 
    { 
     data=a.data; id=++count; print("B(cost B&)"); 
    } 
    ~B(){print("~B()");} 

    operator bool(){ return (bool)data;} 
    B operator+(int i){print("operator+"); return B(data+i);} 
}; 


int B::count=0; 

void main(){ 
    B b(42); 
    B x=b+2; 
    bool z=b+1; 

    getchar(); 
} 

spodziewałem się dostać wydruk konstruktora kopia z B x=b+2 ale to nie robi pokaż. Jakieś pomysły? Dzięki,


Wyjście:

B(int), 1, 42 
operator+, 1, 42 
B(int), 2, 44 
operator+, 1, 42 
B(int), 3, 43 
~B(), 3, 43 

Więc to optymalizacja wartość zwracana?

+3

To prawdopodobnie usunięte. –

+0

Jakiego kompilatora używasz? Jeśli obsługuje C++ 11, powinieneś mieć zdefiniowany konstruktor ruchu - patrz Zasada pięciu. –

+3

Zobacz [copy elision] (http://en.wikipedia.org/wiki/Copy_elision). – juanchopanza

Odpowiedz

1

Wrzuciłem to do GCC naprawdę szybko i zauważyłem to samo zachowanie. Oczywiście kompilator zmienia zachowanie kodu w sposób, jaki uważa za odpowiedni.

Po pierwsze: przypisanie nie jest równe konstruktorowi kopii. Pomyślałem, że używając "=" szukałem operatora = przeciążenia i nie znajdowałem go, a następnie wybierając nowy obiekt B używając jego zwykłego konstruktora, a następnie kopiując go na x używając domyślnego przypisania. Działa to, ponieważ jest to prosta klasa.

Zmieniłem

B x=b+2; 

do

B x(b+2); 

próbować zmusić go do używania konstruktora kopii. Jednak miałem takie samo zachowanie. Następnie przyjrzałem się typowi zwracającemu operatora + i zauważyłem, że zwraca on wartość B. (Nie jest to odniesienie, ale może być ocenione jako odniesienie, o ile przestrzega reguł odwołań do C++ 11). Tak więc kompilator generuje kod w taki sam sposób jak powyżej, dlatego nie korzystamy z konstruktora kopiowania.

Jeżeli zmienisz

B x(b+2); 

do

B x(b); 

Kompilator domyśla się, że konstruktor kopia może być stosowany (aka jest w stanie wygenerować odniesienie do B).

Domyślam się, że kompilator generuje kod ze względu na typ zwrotu operatora +. Prawdopodobnie ma to coś wspólnego z tym, że referencje niestałe traktowane są jako l-wartości tylko w pre C++ 11. A zatem, ponieważ operator + jest wywoływany, nie może utworzyć z niego odwołania stałego, aby przejść do konstruktora kopiowania (ponieważ wynikiem operatora + jest l-wartość). Wykorzystuje więc zwykły konstruktor wraz z automatycznie generowanym operatorem przypisania do wykonania pracy, o którą prosiłeś.

Mam nadzieję, że to pomoże.