Newsgroup: it.comp.lang.c++
Titolo: Scottature da "operator="

Mi sono recentemente scottato con questa cosa: io in una
classe X ho definito un operatore di assegnazione che invece
di accettare un "const X&" accetta un'altro tipo dati in
cui pero' X e' convertibile implicitamente.
Con mia sorpresa la presenza di un "operator=" non ha
impedito la definizione implicita dell'operatore di
assegnazione e quindi assegnando un oggetto X ad un altro
oggetto X non avveniva (come mi sarei aspettato) la
conversione e la chiamata della mia versione ma veniva
invece usata l'implementazione standard.
Ho verificato sui documenti in mio possesso ed effettivamente
questo e' quanto richiede lo standard (se "operator=" non
accetta un "X&", un "const X&" un "volatile X&" oppure un
"const volatile X&" allora non viene ritenuto un operatore di
assegnazione e quindi viene generato automaticamente un
operatore di assegnazione).
Qualcuno sa perche' e' stata introdotta questa regola
che personalmente trovo "strana" ?
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

 che personalmente trovo "strana" ?
a naso per lo stesso motivo per cui e' consigliato di dichiarare 
explicit i costruttori che sono anche convertitori di tipo: per evitare 
livelli inattesi di conversioni
supponendo
class X{
 char c;
public:
 X() : c('\0');
 X(const int& i) : c(i) {}
 X& operator=(const char& C) { c = C; return *this}
 operator const char (const X& x) {return c;}
}
float i = 3.4;
char ii = '4';
int iii = 6;
X a, b, c;
a = X(i);
b = X(ii);
c = X(iii);
tutti e tre i casi sono permessi, ma perche' dovrei chiamare prima la 
conversione a int, poi il costruttore e l'operatore const char e poi 
ancora assegnazione quando tutti e tre i tipi sono direttamente 
riportabili a int, e posso chiamare solo costruttore e ass. default? 
PS: certo non e' un bel codice, ma spero sia chiaro

livelli inattesi di conversioni
Veramente il problema che avevo e' il contrario: io presupponevo
una conversione che invece veniva saltata per colpa della
definizione implicita di un operatore di assegnamento da
parte del compilatore.
Pensandoci un po' mi rendo conto che in effetti la situazione
e' simile a quella dei costruttori. Il costruttore di default
non viene generato se tu dichiari un costruttore... ma il
costruttore di copia invece viene generato comunque a meno
che ce ne sia uno con esattamente quei parametri (o qualsi...
ci sono sempre le varianti permesse con const e volatile).
Questa e' un'altra indicazione chiara che l'operatore di
assegnamento non e' affatto parente degli altri operatori
e che da esso ci si attende una semantica ben precisa.


 cui pero' X e' convertibile implicitamente.
Scusa, cosa significa const X& in questo caso?
Oggetti costanti passati per riferimento?
Grazie
-- 
Luigi
--
bug windows [5] = {"95", "98", "NT", "Me", "2000"};

Oggetti costanti passati per riferimento?
Esatto. Il costruttore di copia e l'operatore di assegnazione
definiti implicitamente dal compilatore accettano come parametro
un oggetto costante passato per riferimento.


 Oggetti costanti passati per riferimento?
si, puntatori a memoria che assicuri di non voler modificare, e che il 
compilatore puo' ottimizzare

 e che da esso ci si attende una semantica ben precisa.
Quasi. Prova a riflettere su questo:
L'operatore di copia e uno dei possibili operatori di assegnamento. Se non e'
definito dall'utente viene predefinito dal compilatore.
Il costruttore di default e il costruttore di copia sono due dei possibili
costruttori. Il costruttore di copia se non e' definito dall'utente viene
predefinito dal compilatore.
Il distruttore se non e' definito dall'utente e' predefinito dal compilatore ed
e' virtuale se una delle classi base ha un distruttore virtuale.
L'operatore indirizzo se non e' definito dall'utente ne nella classe ne nelle
classi base e' predefinito dal compilatore. In questo caso non e' vituale e
restituisce l'indirizzo dell'oggetto.
--
Andrea Ferro
---------
Brainbench C++ Master. Scored higher than 97% of previous takers
Scores: Overall 4.46, Conceptual 5.0, Problem-Solving 5.0
More info 
http://www.brainbench.com/transcript.jsp?pid=2522556

restituisce l'indirizzo dell'oggetto.
Qui ti ho perso... di che stai parlando ? Spero non delle
"asimmetrie" e apparenti "stranezze" del C++. Altrimenti ci
si potrebbe far notte ad elencarle tutte :DDDD




occhio che sono reference, non puntatori.
Anto
--
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.6, higher than 98% of all previous test takers.
C Language: 3.32, higher than 79% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 si potrebbe far notte ad elencarle tutte :DDDD
Sul distruttore credo tu mi abbia seguito. L'operatore di indirizzo altro non e'
che "operator&()" che suppongo tu sappia e' ridefinibile sebbene sia
predefinito. Occhio che su questo operatore esistono veramente delle "stranezze"
alcune delle quali come commenti aperti da discutere in sede di comitato.
Soprattutto legate alle implicazioni che ha sulla definizione dei POD e sulle
implementazioni ammesse per alcune macro tipo offsetof e cose simili. Comunque
le regole di base sono:
1) non ridefinirlo
2) se credi di dover violare 1) ripensaci: e' molto difficile che sia veramente
necessario
3) se nonostante 2) devi veramente violare 1), prova a ripensarci e trovare un
design diverso
4) se nonostante 2) e 3) devi ancora e assolutamente violare 1), fallo, triplica
il budget che avevi per il debugging e scrivi un tema di almeno 10 pagine sul
perche' lo hai fatto e sulle conseguenze che questo ha. Poi prega.


 occhio che sono reference, non puntatori.
un reference viene implementato con un puntatore, alla fin fine. :)

un reference viene implementato con un puntatore, alla fin fine. :)
Ma non lo e'...
--
Andrea Laforgia - walkietalkie(at)
libero.it
#exclude <windows.h>

 wrote in message
news:MyrW6.415$Cq5....@news.infostrada.it...

Anticipo Antonio dicendoti che l'idea e' giusta ma i termini che usi non lo
sono. Un reference e' una cosa. Un puntatore e' un'altra cosa. E sono entrambe
concetti del C++. L'implementazione e' in assembler. Quindi non usa ne reference
ne puntatori. Usa indirizzi.
Pertanto sia i puntatori che i reference sono implementati come indirizzi.
Dire che un reference e' implementato come puntatore e' come dire che e'
implementato come intero. Infatti in assembler questo e' quasi certamente vero
(quasi, perche' dipende dall'HW).
Qundi quello che Antonio voleva dirti e' che la tua affermazione: "puntatori a
memoria che assicuri di non voler modificare", non e' corretta. E infatti
avrebbe dovuto essere "indirizzi di memoria che assicuri di non voler
modificare".


predefinito.
Le stranezze di operator&() sono effettivamente molte ... su
questo ho anche segnalato tempo fa a Scott Meyers una
imprecisione su questa parte di un item di Effective C++; ho
scoperto che si trattava di un problema noto ma non ancora
listato nelle errata ufficiali.


 prega.
:)))))))))))


Azz. Potere del cut&paste. Avevo scritto prima il copy operator (anche se poi mi
pare di averlo messo dopo nel messaggio).
Comunque hai ragione. Il copy constructor di X puo' essere solo un X& con
qualunque cv-qualificazione. Mentre il copy operator puo' anche essere di tipo
X.
Tre cose che potrebbero interessare e che non avevo detto sono:
1) copy constructor e copy operator non devono essere template
2) copy operator non deve essere statico (il construttore non puo' esserlo,
ovviamente)
3) lo standard definisce il copy constructor in due punti, e in uno sbaglia
(dimentica di dire che il parametro del copy construtor puo' essere volatile).


 le versioni di default.
Perche' come ti dicevo non sempre la cosa e' verificabile al momento di generare
la classe. Per cui si e' definito che per copiare una classe assegnadola ad
un'altra istanza di se stessa si debba fare uso di un operatore di copia (che e'
uno dei possibili operatori di assegnamento). Che sia in alcuni casi, non tutti
verificabili all'atto di compilare la classe, possibile assegnare un oggetto di
classe X ad un altro oggetto di classe X senza fare uso dell'operatore di copia
resta vero. Ma dato che il compilatore non puo' essere certo della cosa
compilando X e deve essere certo che la copia sia possibile, l'operatore di
copia viene comunque generato. E a questo punto la tua conversione non avviene
semplicemente a causa delle regole di overload resolution. Il che non significa
che non puoi ottenere quello che vuoi. Semplicemente che non avviene per
default. Non ti resta che esplicitare la cosa:
class B;
class A {
public:
    A& operator=(const B&);
    A& operator=(const A&);
};
class B {
public:
    B(const A&);
};
inline A& A::operator=(const A&r) { return operator=(B(r)); }


definita in un'altra classe. Immagina:
A questo non avevo pensato... e si tratta di un'ottima ragione.
Fra l'altro questo discorso delle dichiarazioni forward mi ha
fatto venire un sospetto e ho scritto questo programma di test:
  #include <iostream>
  struct X;
  struct Y
  {
    Y() { }
    Y(const X&) { }
  };
  #if defined(BEFORE)
  struct X
  {
    operator Y& () const
    {
      static Y y;
      return y;
    }
  };
  #endif
  void foo(const Y& y)
  {
    std::cout << "versione const Y&\n";
  }
  void foo(Y& y)
  {
    std::cout << "versione Y&\n";
  }
  void test(const X& x)
  {
    foo(x);
  }
  #if !defined(BEFORE)
  struct X
  {
    operator Y& () const
    {
      static Y y;
      return y;
    }
  };
  #endif
  int main()
  {
    X x;
    test(x);
    return 0;
  }
Quello che succede con g++ e' che compilando senza definire BEFORE
viene chiamata la versione "const Y&" mentre definendo il simbolo
BEFORE viene chiamata la versione "Y&".
Non pensavo che si potesse creare una situazione simile a questa
(ovvero che se una classe viene non viene definita completamente
allora il codice compila lo stesso ma chiama altre funzioni rispetto
a quelle che avrebbe chiamato con una definizione completa)... ho
l'impressione che la possibilita' di accettare definizioni parziali
e di definire operatori di conversioni sia "da" che "verso" crei
qualche problema dal punto di vista filosofico.
Non ne sono sicuro perche' provando con BCC55 la versione senza
BEFORE compila e chiama "const Y&" mentre quella con BEFORE genera
un errore; con VC++ invece accade esattamente il contrario (la
versione senza BEFORE non compila mentre quella con BEFORE compila
e chiama "Y&").
Chi avra' ragione: g++, BCC55, VC++ oppure Knuth ? (mi sembra di
aver letto che secondo Knuth un compilatore C++ deve purtroppo
necessariamente tirare ad indovinare tanto e' formalmente imprecisa
e poco rigorosa la sintassi C++)
Beh... comunque non male come portabilita' del C++... eh ? (e
questo senza nemmeno valicare il confine della temibile terra
di nessuno dei template ;) )


 modificare".
Hai ragione su tutto, tranne che su una cosa: quest'ultima
affermazione che contesti non l'avevo scritta io, ma SuPeR.  ;)

 come un intero?? (Domanda seria)
Ad esempio tutti i sistemi che gestiscono la memoria in modo segmentato.
Ad esempio il buon vecchio 8086 aveva uno spazio di indirizzamento di 20
bit, ma gestiva solo word di 16. Quindi gli indirizzi erano
rappresentati da 16 bit di segmento e 16 bit di spiazzamento all'interno
del segmento stesso (ovviamente esistevano molti modi di riferirsi allo
stesso indirizzo fisico).
Ciao,
Nicola

 fatto venire un sospetto e ho scritto questo programma di test:
... snip
Problema interessante. Mi sa che dovro' indagare cosa dice lo standard in merito
(appena ho tempo).
Se qualcuno ha un'idea ... si faccia avanti.


 affermazione che contesti non l'avevo scritta io, ma SuPeR.  ;)
Vero. Ma in un thread poi si finisce per commentare insieme quello che tu scrivi
e quello a cui tu stesso stai replicando. E comunque ripeto: non ho contestato
nulla. Ho solo precisato.


pubblicamente (o un alias di T stessa).
Perche' dici che ha bisogno dell'assegnamento ? Credevo di aver
capito che quella che viene usata implicitamente e' sempre
l'inizializzazione da copia (vedi passaggio di parametri e return).
Quand'e' che il compilatore si permette di chiamare operator= senza
che lo abbia chiesto io esplicitamente ?
Se parliamo delle funzioni di libreria allora il discorso non mi
sembra valido. Alcune di quelle funzioni richiedono ad esempio
che le classi prevedano un ordinamento... ma questo non
autorizza il compilatore ad inventarsi a tutti i costi un
ordinamento di default.
Tutto sommato io vedo ancora una differenza marcata fra quello
che e' il C++ "core" e quello che e' la libreria standard.
Il comportamento e' invece che se chiamo una funzione che prevede
un ordinamento e la mia classe non lo definisce allora ottengo un
errore di compilazione (cosa a mio parere sensata).
Riguardo invece ai problemi di conversioni implicite definite
in altre classi di cui non e' detto che si conosca la definizione
completa invece hai secondo me ragione. Questo complica le cose
(e i comportamenti difformi di BCC55/VC++/g++ su questo punto mostra
che a quanto pare le complica anche per chi scrive compilatori)


 che lo abbia chiesto io esplicitamente ?
Lo standard infatti non garantisce solo le operazioni che vengono fatte
implicitamente ma anche che ci siano due operazioni esplicite che sono sempre
permesse. Ovvero e' garantito che tu possa scrivere:
void foo(T& a, const T& b)
{
    a=b;
}
Lo stesso discorso vale per loperatore & che e' garantito esistere (anche se non
e' garantito il tipo che ritorna etc).
In altre parole il copy operator non e' garantito perche' serve al compilatore
ma perche' era garantito in C per le struct. Il fatto che venga eseguito solo se
lo usi esplicitamente non conta.
Semmai la domanda sarebbe un'altra: perche' la stessa cosa non vale per il
default constructor. Ma questo sinceramente non lo so.


default constructor. Ma questo sinceramente non lo so.
Secondo me il default constructor deve esistere per
compatibilita' con il C; quello viene in pratica chiamato
implicitamente dal compilatore quando dichiari una istanza.
Una volta che pero' in una struttura hai definito un costruttore
non c'e' necessita' di mantenere questa compatibilita'.
Come scelta mi sembra ragionevole...
Sull'operatore di assegnazione invece sono confuso... io avrei
trovato piu' logico che se non esiste un operator= nella classe
allora ne viene creato uno standard (per compatibilita' e per
comodita'); se invece esiste anche un solo operatore di
assegnazione allora questa versione standard non viene creata.
Il fatto che non venga ereditato invece e' correttissimo...
copiare solo la parte base non avrebbe quasi mai senso.
Una buona giustificazione potrebbe essere davvero la presenza di
una definizione forward... pero' non ho pensato a fondo alla cosa:
ho l'impressione (a "pelle") che la presenza delle conversioni
implicite da tipi non definiti completamente sia pero' fonte di
problemi in genere.
Sull'operatore "&" lo standard e' chiaro: l'operatore puo' essere
usato su tipi non completamente definiti pero' se di questo
operatore esiste per quel tipo un overload allora il comportamento
e' undefined e non e' richiesta diagnostica su questo problema
(leggi: "se proprio vuoi cercarti grane io non ti fermo sicuro").


 problemi in genere.
La forward entra in gioco dopo. Ovvero dopo che hai preso la decisione che un
copy operator deve esistere, allora, a causa della forward, la definizione di
cosa sia un copy operator si restringe e non ammette l'uso di operatori di
assegnamento da tipi per cui esiste un cast implicito. Ma si sarebbe potuto
benissimo dire che se esiste un operatore di assegnamento qualunque allora il
copy operator non viene garantito (come per il default costructor e come
vorresti tu). Ma non e' cosi.


 nulla. Ho solo precisato.
Non me l'ero presa! non me la prendo mai pe
r le cose importanti, solo
per le inezie ;)

 E invece no!
La coerenza ha senso solo tra contesti paragonabili. Il costruttore di
default ed il costruttore di copia svolgono ruoli diversi. Mentre il
meccanismo di copia fa parte della semantica standard delle classi,
tant'e' vero che la sua disabilitazione tramite dichiarazione privata e'
sostanzialmente un trucco, l'inizializzazione di una classe e' un
aspetto specifico della sua semantica e l'intenzione del suo disegnatore
ha il sopravvento, salvo fornire un meccanismo di riserva.
Ciao,
Nicola

 una modalità in più.
Anche il discorso della paginazione della memoria (e relativa virtualizzazione)
non e' un vero "Modo" a se stante, ma una cosa che puoi gestire o meno e sui
nuovi processori puoi anche decidere fra diverse granularità, ovvero dimensioni
della pagina.
Cercavo di semplificare al massimo per avere un messaggio quasi intellegibile
anche per chi non conosce niente di architetture dei microprocessori e voleva
farsi una "idea generale". Nel mio post c'erano una marea di imprecisioni
tecniche e distinguo non fatti (pensa all'indirizzamento rel-mode che e'
contemporaneamente segment+offset ma anche 'flat' data la disposizione fisica
prefissata dei segmenti da 64k con overlap ogni 16).
Ma se hai scritto codice assembler system level per gli Intel, queste cose le
sai. Come ha fatto a non venirti in mente che in una architettura a memoria
segmentata non c'e' una corrispondenza diretta fra puntatori ed interi
effettivamente e' un mistero.


 ha il sopravvento, salvo fornire un meccanismo di riserva.
Probabilmente hai ragione ed e' proprio questa considerazione che ha portato
alle specifiche che abbiamo.
Anche se IMHO dicendo che l'inizializzazione di una classe e' un aspetto della
sua semantica, allora l'inizializzazione per copia rientra nella semantica
dell'inizializzazione piu' che nella semantica di copia.
Ovvero filosoficamente l'intero si inizializza con
int i(8);
e non con
int i=8;
Con questo non intendo contestare la regola sintattica per cui le due scritte
sono equivalenti. Ma il fatto filosofico che l'inizializzazione di i avvenga
"partendo da un valore della stessa classe" e non come copia del valore su un
"nuovo i".
Quindi secondo il tuo ragionamento potrei giustificare una regola che dice che
l'operatore di copia di comporta come da standard mentro il costruttore di copia
segue la regola dei costruttori (e come quello di default non e' definito se
esiste un qualunque altro costruttore). Il fatto che tale regola conflita con
gli usi intrinsechi del costruttore di copia non dovrebbe contare: la semantica
di costruzione dipende dalla specifica classe, quella di copia e' intrinseca al
concetto di classe. Pertanto il compilatore si ingegni a costruire il parametro
secondo la semantica della mia classe (se puo', per esempio con il costruttore
di default) e poi applichi la semantica di copia.
Il risultato e' brutto, inefficiente, difficile da integrare con altre parti
delo standard? Forse. Ma e' coerente con la filosofia da te descritta.
Resto quindi dell'idea che il costruttore per copia si comporta come si comporta
perche' la semantica di inizializzazione non e' del tutto libera. E a questo
punto non vedo perche' non includere la costruzione per default, che fa
anch'essa parte della semantica di inizializzazione delle classi C ed e' persino
usata intrinsecamente dal compilatore (array) non debba essere mantenuta
anch'essa (salvo il discorso del costruttore privato o dichiarato ma non
definito).


 definito).
Perche' per fortuna il C++ e' uno strumento pratico e non una cosmogonia
post-platonica. Hai capovolto le cose, anteponendo per importanza un
artifizio come la dichiarazione privata del costruttore di copia alla
definizione di un costruttore diverso da quello di default. Quest'ultimo
e' una delle estensioni primarie del C++ sul C: fornire un meccanismo
che permetta di garantire che ogni istanza di una classe parta da uno
stato definito *utile* e non generico, anche quando per definire tale
stato utile e' indispensabile passare dei parametri.
L'ordine delle priorita' e':
- Permettere di garantire che tutte le istanze partano da uno stato
  definito e utile: Da questo deriva la possibilita' di definire un
  costruttore di default.
- In molti casi l'inizializzazione di default membro a membro e'
  adeguata: da questo deriva la sintesi del costruttore di default.
- Spesso pero' non e' possibile costruire uno stato utile senza avere
  dei parametri iniziali: da questo deriva la disabilitazione della
  sintesi del costruttore di default. La considerazione di Stroustrup,
  che io condivido, e' che nella maggior parte dei casi in cui viene
  definito un costruttore dotato di parametri e' perche' la costruzione
  di default e' inadeguata.
Per la costruzione di copia il discorso e' diverso:
- Nella maggior parte dei casi la copia membro a membro e' adeguata:
  di qui la sintesi del costruttore di copia.
- Talvolta pero' questo non e' adeguato, ad esempio in presenza di
  puntatori ad oggetti di cui si ha il possesso: da questo deriva la
  possibilita' di definire ad hoc il costruttore di copia.
- In alcuni casi particolari non si vuol proprio permettere la copia:
  per questo qualcuno ha inventato il trucco di dichiarare il
costruttore
  di copia privato e di non definirlo. Anche qui concordo con la
  valutazione di Stroustrup circa l'importanza relativa dei diversi
casi.
Sono abbastanza convinto che alcune delle contorsioni del C++ siano
dovute ad un'esagerata inclinazione di B.S. per il pragmatismo, a
scapito dell'eleganza formale. Tu pero' Andrea tendi ad eccedere nella
direzione opposta e nelle tue elucubrazioni ti disinteressi
completamente dello scopo delle cose, in nome di una coerenza formale,
che francamente penso tu sia l'unico a vedere: miopia nostra o
allucinazioni tue?
Di tanto in tanto dovresti ricordarti del Rasoio di Occam: Entia non
sunt multiplicanda praeter necessitatem (ovvero: non aggiungere al
ragionamento elementi che non siano necessari).
Ciao,
Nicola

 ragionamento elementi che non siano necessari).
Su questa linea si potrebbe dire che e' assurdo il fatto che il costruttore di
copia e l'operatore di copia siano "forzati". Io invece accettavo che lo
standard avesse "aggiunto comportamenti non necessari (sebben comodi)" ma
perche' non ne abbia aggiunto un'altro (stesso comportamento del costruttore di
default come di quello di copia). Non ho ancora visto un motivo per il
comportamento tenuto dal compilatore per il costruttore di copia e per
l'operatore di copia che non sia anche valido per il costruttore di default.


definito).
dato che la compatibilità all'indietro con il C porta questi problemi,
non sarebbe stato meglio separare nettamente gli usi di struct e
class? Dichiarando una struct si sarebbero avuti copy ctor e operator=
come in C, mentre per class si sarebbe potuta adottare una politica
diversa e magari più coerente.


 l'operatore di copia che non sia anche valido per il costruttore di default.
Il nocciolo della questione e': come si determinano i valori che
dovranno avere i membri della classe al termine della costruzione? Nel
caso della costruzione per copia esiste una scelta ragionevole
indipendente dalla semantica specifica della classe in questione: i
valori dei corrispondenti membri dell'oggetto copiato. Questo tra
parentesi vale anche per il copy assignment operator, che immagino sia
quello che chiami operatore di copia.
Nel caso invece del costruttore di default qualsiasi scelta a priori e'
arbitraria. Il programmatore potrebbe fregarsene, e tenersi il
costruttore di default sintetico. Pero' la definizione di un qualsiasi
costruttore e' presa come una manifestazione dell'intenzione dello
sviluppatore di far si che tutte le istanze della classe siano
inizializzate secondo il suo criterio e per questo la sintesi del
costruttore di default e' disabilitata.
Certo, il programmatore potrebbe non preoccuparsi dell'effettiva
inizializzazione di *tutte* le istanze della sua classe, ma
semplicemente fornire il costruttore aggiuntivo come meccanismo di
convenienza: questo caso pero' e' presumibilmente considerato meno
probabile.
D'altra parte se le situazioni fossero invertite il primo caso
introdurrebbe maggior rischio di errore: bisognerebbe ricordarsi di
disabilitare esplicitamente il costruttore di default, ed il compilatore
non potrebbe segnalare un'eventuale dimenticanza.
Ciao,
Nicola

 diversa e magari più coerente.
Possibile si, ma il problema resterebbe. Solo sarebbe confinato alle struct. E
avresti poi dei problemi supplementari in caso di aggregazione fra struct e
class, sia essa per composizione o per inheritance (di fatto stai proponendo di
introdurre una ulteriore asimmetria).


 non potrebbe segnalare un'eventuale dimenticanza.
Se e' per questo devo anche ricordarmi di disabilitare esplicitamente il
costruttore per copia e se non lo faccio il compilatore non mi segnala la
dimenticanza.


 dimenticanza.
Salvo che e' meno probabile disabilitare la costruzione per copia di
quanto non sia definire un costruttore di default.
Ciao,
Nicola

 effettivamente e' un mistero.
sarà il caldo? :) comunque un indirizzo, nella memoria segmentata, è
comunque identificato da una coppia di elementi appartenente
all'insieme degli interi, quindi ho ragione io! ;)

 all'insieme degli interi, quindi ho ragione io! ;)
Una coppia di interi non e' un intero. A meno che tu non possa definire una
relazione fra ciascun valore possibile della coppia e un valore intero che
mantenga valide le relazioni d'ordine stretto intrinseche all'aritmetica dei
puntatori e a quella degli interi. In tal caso hai una funzione I che mappa dal
dominio dei puntatori (coppie di interi) al dominio degli interi ed due
relazioni che legano le due operazioni dell'artimetica dei puntatori con
l'algebra degli interi:
I(p+o)=I(p)+k*o
p-q = (I(p)-I(q))/k
dove 'p' e 'q' sono puntatori (omogenei), 'o' un intero, 'p+o' e 'p-q' le due
operazione possibili in aritmetica dei puntatori, e 'k' una costante dipendente
dal tipo di 'p' (e 'q' che infatti sono omogenei).
Questo tu lo puoi fare solo se p e q oltre ad essere omogenei hanno lo stesso
segmento o se e' garantita (perche i segmenti overlappano) la loro distanza in
indirizzamento logico. Solo in tal caso puoi definire la funzione I (piu'
precisamente solo in tal caso puoi definire la seconda delle due operazioni di
aritmetica dei puntatori. Altrimenti i puntatori non sono correlati).


 quanto non sia definire un costruttore di default.
Stai dicendo che la presenza di un costruttore qualunque e' piu' probabile che
implichi la non validità del costruttore di default sintetizzato che non quella
del costruttore per copia sintetizzato? Se e' cosi' non sono d'accordo.


 dal tipo di 'p' (e 'q' che infatti sono omogenei).
tutte cose che in questi processori puoi fare, no?

 tutte cose che in questi processori puoi fare, no?
Idem come sopra. In real mode si. In protected mode no (almeno che non
stabilisci tu che i segmenti siano mappati in tal modo, ma non e' una cosa
"enforced"). Ovvio che se poi fai come windows per cui un processo di fatto
"vede" un modello "flat" ... Ma e' un processo utente. Il sistema operativo se
vuole fa ben altro (se vuole).


 essendo segmented, in realtà ha un mappaggio flat.
ooooh la', adesso ho capito! sono duretto ma alla fine ci arrivo ;).
Ti ringrazio per la pazienza!