Newsgroup: it.comp.lang.c++
Titolo: Chiarimenti sul costruttore di copia

Sarà anche l'ora tarda ma ho un dubbio che non riesco a chiarirmi:
il seguente pezzo di codice (semplificato all'osso) compila
perfettamente con il Comeau on-line ma non con il gcc 3.4.2
<code>
class Base
{
public:
    Base(){}
    private:
    Base(const Base&){}
};
class Derived: public Base
{
public:
    Derived() {}
    explicit Derived(int) {}
};
int main()
{
    Derived a;
    int b;
    a = Derived(b);
}
</code>
L'errore restituito dal gcc è il seguente:
pippo.cc: In copy constructor `Derived::Derived(const Derived&)':
pippo.cc:6: error: `Base::Base(const Base&)' is private
pippo.cc:20: error: within this context
Quale dei due compilatori ha ragione?
Grazie, ciao.
-- 
BSD is for UNIX lovers -- linux is for Windows haters.


Credo che gcc stia richiamando il costruttore di copia quando non dovrebbe.
Infatti
Derived a; //chiama  costr. di base Base() eCostr.derived per a
int b;
a = Derived(b); //chiama Costr.di base Base(), Costr. Derived(int) poi
l'operatore di assegnamento
In questo caso infatti non dovrebbe essere richiamato il costruttore di
copia, bensě l'operatore di assegnamento '=', che il compilatore ha creato
per te e che ha lo scopo di copiare bit a bit l'oggetto creato da Derived
(b) in a.
Ciao
Andrea

 Credo che gcc stia richiamando il costruttore di copia quando non
dovrebbe.
Comunque provando a compilare il codice con gcc versione 3.2 (Red Hat Linux
8.0), non dà alcun problema!
Probabilmente non si tratta di compilatore.... :o)

 pippo.cc:20: error: within this context
Quello che il compilatore ti sta dicendo è che non può, all'interno del
costruttore di copia(implementato dal compilatore stesso) di Derived, fare
una copia di un oggetto della classe Base, in quanto il suo costruttore di
copia è stato dichiarato privato.
Dichiarare private il costruttore di copia significa che si vuole che la
classe a cui appartiene venga copiata, come hai appena visto.
Quindi il compilatore, nel momento in cui deve fare la copia di un oggetto
Derived, non essendoci un costruttore di copia per quella classe, se ne
costruisce lui uno, ma, nel momento in cui deve copiare la parte che si
riferisce a Base, si accorge che non può farlo perché la classe Base, ha il
costruttore di copia privato. Giustamente.
Se vuoi che Derived sia copiabile, allora non hai altra scelta che dare un
costruttore di copia pubblico a Derived, oppure dichiare protected il
costruttore di copia di Base, questo dovrebbe renderlo accessibile alle
classi derivate.
Ciao,
Maurizio.

 Dichiarare private il costruttore di copia significa che si vuole che la
ops, volevo dire che NON si vuole
Ciao,
Maurizio.

 Linux 8.0), non dà alcun problema!
Non dà alcun problema nemmeno con la 3.3, mentre con la 3.4.1 si comporta
come nel caso presentato dall'OP. Togliendo il 'private' e tracciando le
chiamate, si può vedere che il costruttore copia non viene in realtà
chiamato. Direi che è un bug.
Max

 da Derived (b) in a.
Non bit a bit, mà elemente a elemente.
--
James Kanze           GABI Software         
http://www.gabi-soft.fr
Conseils en informatique orientée objet/
                   Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, 
+33 (0)1 30 23 00 34

 Non bit a bit, mà elemente a elemente.
Volendo essere precisi il compilatore eseguirebbe la copia membro a membro
(memberwise) per gli oggetti composti da altri oggetti, mentre esegue la
copia bit a bit (bitwise) per i tipi primitivi e i puntatori.
Guarda "Rules for Declaring Constructors":
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang98/html/_pluslang_rules_for_declaring_constructors.asp
per maggiori informazioni.
Ciao
Andrea

 
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang98/html/_pluslang_rules_for_declaring_constructors.asp
Se dice qualcosa di diverso dalla copia membro a membro non guardarlo.
        Mauro

 Se dice qualcosa di diverso dalla copia membro a membro non guardarlo.
Scusa ma alla microsoft sapranno come fanno il loro compilatore... (almeno
credo! non ne sono poi cosě sicuro... :o)

 Il compilatore esegue sempre la copia membro a membro.
Allora mi ricordavo bene... prendendo pagina 496 di Thinking in C++ Vol.1:
"To create a copy-constructor for a class that uses composition (and
inheritance, which is introduced in Chapter 14), the compiler
recursively calls the copy-constructors for all the member objects
and base classes. That is, if the member object also contains another
object, its copy-constructor is also called. So in this case, the
compiler calls the copy-constructor for WithCC. The output shows
this constructor being called. Because WoCC has no copyconstructor,
the compiler creates one for it that just performs a
bitcopy, and calls that inside the Composite copy-constructor. The
call to Composite::print( ) in main shows that this happens because
the contents of c2.wocc are identical to the contents of c.wocc. The
process the compiler goes through to synthesize a copy-constructor
is called memberwise initialization."
la copia membro a membro non identifica altro che un processo ricorsivo
che termina con la copia bit a bit dei tipi più semplici.
Ciao, Andrea


Pero' questo non significa che il loro compilatore poi rispetti lo 
standard, che e' quello di cui si dovrebbe poi parlare qui :P
-- 
Mat/tia Belletti - Undergraduate student @ 
cs.unibo.it
ICQ: 33292311    - email: 
mbel...@cs.unibo.it
IRC: RedGlow     - site(s): 
http://mbellett.web.cs.unibo.it/
Linux registered user 299762 @ Linux registered machine 213003

 copia è stato dichiarato privato.
Solo che il costruttore di copia non viene chiamato in causa.
C'è una questione un po' sottile su questo punto.
<code>
class A
{
    A(const A&) {}
public:
    A() {}
};
int main()
{
    A a = A();
}
</code>
In questo caso il costruttore di copia non viene chiamato ma lo 
standard richiede comunque che il costruttore di copia sia accessibile.
Dichiarandolo privato il codice sopra non deve compilare:
"ComeauTest.c", line 11: error: "A::A(const A &)" is inaccessible
         (Even though the copy was eliminated, the standard
         still requires it to be accessible)
    A a = A();
          ^
 
Non so però come siano le cose nel caso A venga derivata, secondo il
Comeau non c'è più questo requisito richiesto dallo standard, perché il
codice compila senza errori:
<code>
class B: public A
{
};
int main()
{
    B a = B();
}
</code>
Ciao.


 (b) in a.
In effetti, come ha notato Max, non viene chiamato il costruttore di
copia, però il fatto che sia inaccessibile provoca comunque un errore
con il GCC 3.4.2.
Ne discuto un po' più approfonditamente nell'altro post.
Ciao.


 </code>
Questo non mi torna; la pretesa che il costruttore di copia sia
accessibile deve valere anche per B. Il problema e' che il costruttore
di copia di B non e' sintetizzabile, perche' quello di A e' privato.
E' un po' come se scrivessimo
class B: public A
{
  public:
    B(const B &);
};
Senza implementarlo. Ed infatti il Comeau compila anche questo. Nota
poi che nel codice originale c'e' un assegnamento e non
un'inizializzazione e quindi, come dicevi tu, il costruttore di copia
non dovrebbe entrarci per niente. A me sa tanto di baco del g++, che
varrebbe la pena di segnalare.
Ciao,
Nicola

 standard, che e' quello di cui si dovrebbe poi parlare qui :P
Nì, infatti anche il modo in cui vengono copiati gli oggetti in un
costruttore di copia vengono definiti nello standard ANSI e il compilatore
microsoft (.NET/VS) secondo quel documento rispetta lo standard.
Siccome su questo argomento anche io ho avuto il dubbio su quale fosse
effettivamente lo standard, ieri ho fatto una ricerchina in internet e ho
trovato un bel pò di documenti interessanti. Uno per esempio è il seguente,
che credo chiarisca una volta per tutte la differenza tra memberwise copy e
bitwise copy:
DEEP COPYING AND SHALLOW COPYING
The terms "deep copy" and "shallow copy" refer to the way objects are
copied during the invocation of a copy constructor or assignment
operator. In a deep copy (also called "memberwise copy"), the copy
operation respects object semantics. For example, copying an object
that has a member of type std::string ensures that the corresponding
std::string in the target object is copy-constructed from the target's
string object:
class A
{
 string s;
};
A a;
A b;
a=b; /*deep copy*/
When assigning b to a, the compiler-generated assignment operator of
class A first invokes the assignment operator of class std::string.
Thus, the members a.s and b.s are well defined. On the other hand, a
shallow copy (also called a "bitwise copy") simply copies chunks of
memory from one location to another. A memcpy() operation is an
example of a shallow copy. Because memcpy() does not respect object
semantics, it won't invoke the copy constructor of an object.
Therefore, you should never use memcpy() to copy objects. Use it only
when copying POD (Plain Old Data) types: ints, floating point numbers,
and dumb structs.
---------------------------------------------- 
Danny Kalev is a system analyst and software engineer with more than
ten years of experience, specializing in C++ and object-oriented
analysis and design. He is a member of the ANSI C++ standardization
committee and the author of The ANSI/ISO C++ Professional Programmer's
Handbook (Que,1999).
---------------------------------------------- 
Ciao
Andrea

A me sa tanto di baco del g++, che varrebbe la pena di segnalare.
Quoto :o)
Andrea

 Se dice qualcosa di diverso dalla copia membro a membro non guardarlo.
Si può ch'è vecchio. Nei primi C++ era ben bit a bit.


 accessibile. Dichiarandolo privato il codice sopra non deve compilare:
In questo caso depende de l'implementazion se il costruttore di copia
viene chiamato. Non chiamarlo è un'optimisazione molto frequente
permesso espliciamente nel standard.
Mà in tuo codice si tratte d'una definizione con initialisazione. Nel
codici originale si trattava di un'assegnamento a una variabile definita
primo. Il probleme è qu'il compilatore vuole un costruttore di copia per
fare un'assegnamento. Chi è un errore nel compilatore.


 
Non da nessun problema neanche con  gcc 3.3.3, qualcuno ha provveduto a
segnalare il BUG? :))