2009-10-13 5 views
6

Uno di voi può spiegare perché la seguente parte di codice non viene compilata?Errore in caso di fotocopiatrice privata con operatore di assegnazione pubblica

#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
private: 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo foo; 

    foo = Foo(); 
} 

L'errore che riceve:

$ g++ -o copy_ctor_assign copy_ctor_assign.cc && ./copy_ctor_assign 
copy_ctor_assign.cc: In function 'int main()': 
copy_ctor_assign.cc:10: error: 'Foo::Foo(const Foo&)' is private 
copy_ctor_assign.cc:17: error: within this context 

Nota: quando rimuovo il privato: parola chiave il codice viene compilato, ma il ctor copia viene mai chiamato. Allora perché errare quando è privato?

Non sono sicuro se è importante, ma sto usando:

$ g++ --version 
g++ (GCC) 4.1.2 20080704 (Red Hat 4.1.2-44) 
Copyright (C) 2006 Free Software Foundation, Inc. 
+1

FWIW: il codice non co mpile se assegni un oggetto Foo precedentemente creato invece di un oggetto temporaneo. Cioè 'foo = bar;' invece di 'foo = Foo();'. – sepp2k

risposta

5

Stai inizializzazione di un riferimento dal temporanea.
Gli stati standard:
Il temporaneo deve essere inizializzato (8.5.3 par 5) "utilizzando le regole per l'inizializzazione della copia non di riferimento (8.5)".

La copia viene rimossa temporaneamente (consentito dallo standard 12.8 par 5).
Tuttavia, lo standard indica chiaramente (12.2 par 1):
"Anche quando viene evitata la creazione dell'oggetto temporaneo (12.8), tutte le restrizioni semantiche devono essere rispettate come se fosse stato creato l'oggetto temporaneo. [Esempio: pari se il costruttore di copia non viene chiamato, tutte le restrizioni semantiche, quali l'accessibilità (clausola 11), devono essere soddisfatti.]"

(anche, quando alla ricerca della citazione giusta, pensa che questa duplicate :)

Modifica: aggiungendo la posizione pertinente dallo standard

+0

Questa risposta è corretta, ma cita la parte errata di '8.5.3 para 5' (nel nostro caso, abbiamo tipi di classi e tipi di riferimento compatibili, quindi i * precedenti * punti elenco dovrebbero essere presi). Il più importante è il precedente e dice se copiare o meno è definito dall'implementazione e quindi "Il costruttore che verrebbe usato per fare la copia deve essere richiamabile indipendentemente dal fatto che la copia sia effettivamente eseguita". Per C++ 0x, l'implementazione non può più copiare e non richiede più un costruttore di copia. –

+0

I stand correct :) grazie –

+0

Grazie, ho imparato qualcosa di nuovo oggi. – sdumi

1

Copia CTOR viene chiamato quando:

  1. passaggio di un oggetto dal valore come parametro di una funzione,
  2. restituire un oggetto da una funzione.

Quindi si sta certamente facendo uno o entrambi questi casi da qualche parte nel codice. È necessario impostare Copy Ctor come pubblico o evitare i 2 casi precedenti.

+0

Lo ha fatto. Prova a compilare il suo codice. L'errore viene generato (senza alcun codice aggiuntivo) –

0

Copia costruttore sarebbe chiamato se si scrive

Foo foo; // normal constructor 
Foo foo1(foo); //copy constructor 

Nel tuo caso, prima il costruttore di default viene chiamato e quindi l'operatore = metodo.

+0

Allora perché il suo codice non viene compilato? – sepp2k

+0

Forse il suo codice non viene compilato con Werror? ;) – UncleBens

3

Supponendo che il codice che hai postato è l'unico codice nel progetto, e non c'è passaggio segreto di Foos per valore in corso da nessuna parte, tutto quello che riesco a capire è che gcc sta ottimizzando

Foo foo; 
foo = Foo(); 

a

Foo foo = Foo(); 

... che è infondata, come prima forma è un default-costrutto e un'assegnazione, mentre il secondo è uguale a

Foo foo(Foo()); 

... che è chiaramente una copia della costruzione. Se ho ragione, il costruttore di copie non viene eseguito perché GCC può ottimizzare il temporaneo ridondante; questo è permesso dalle specifiche C++.

In generale, non è una buona idea avere operatori di assegnamento e copiatori di costruttori a diversi livelli di protezione; come hai visto, i risultati possono essere non intuitivi.

+0

gcc non può ottimizzare i costruttori in questo modo, poiché hanno effetti collaterali (il 'cout's). Se gcc lo fa, è un bug. – CAdaker

+0

@CAdaker: no. La rimozione dei temporizzatori ridondanti è un caso speciale e lo standard C++ consente esplicitamente di elidere la costruzione della copia in tali circostanze. –

+0

Anche quando i temporari hanno costruttori e distruttori non banali? Sembra completamente folle. – CAdaker

4

Questo codice viene compilato con gcc 4.3.3 e 4.4.1. Forse è solo un bug in gcc 4.1?

+0

Puoi provare a ricompilare in queste versioni usando -Wall? Grazie –

+0

Ottengo avvertimenti su operator = non restituire un valore, ma altrimenti niente. – CAdaker

+0

Non funziona per me: usare g ++ (GCC) 3.4.4 –

-1
#include <iostream> 

using namespace std; 

class Foo 
{ 
public: 
    Foo() { cout << "Foo::Foo()" << endl << endl; } 
    Foo& operator=(const Foo&) { cout << "Foo::operator=(const Foo&)" << endl << endl; } 
    Foo(const Foo& b) { *this = b; cout << "Foo::Foo(const Foo&)" << endl << endl; } 
}; 

int main() 
{ 
    Foo f1;// default constructor called 

    Foo f2 = f1; //copy constructor called 
} 

Check this, in Foo f2=f1; (f2 viene creato utilizzando la copia costruttore)

+0

Cosa stai cercando di dire nel codice sopra? Alla domanda è stato chiesto perché si verifica un errore di compilazione quando il costruttore di copie è privato. Hai appena dato un esempio di costruttore e copiatrice di default. – Jagannath