Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria
vivo X300 Pro rappresenta un'evoluzione misurata della serie fotografica del produttore cinese, con un sistema di fotocamere migliorato, chipset Dimensity 9500 di ultima generazione e l'arrivo dell'interfaccia OriginOS 6 anche sui modelli internazionali. La scelta di limitare la batteria a 5.440mAh nel mercato europeo, rispetto ai 6.510mAh disponibili altrove, fa storcere un po' il naso
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo
Lenovo Legion Go 2 è la nuova handheld PC gaming con processore AMD Ryzen Z2 Extreme (8 core Zen 5/5c, GPU RDNA 3.5 16 CU) e schermo OLED 8,8" 1920x1200 144Hz. È dotata anche di controller rimovibili TrueStrike con joystick Hall effect e una batteria da 74Wh. Rispetto al dispositivo che l'ha preceduta, migliora ergonomia e prestazioni a basse risoluzioni, ma pesa 920g e costa 1.299€ nella configurazione con 32GB RAM/1TB SSD e Z2 Extreme
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti
A re:Invent 2025, AWS mostra un’evoluzione profonda della propria strategia: l’IA diventa una piattaforma di servizi sempre più pronta all’uso, con agenti e modelli preconfigurati che accelerano lo sviluppo, mentre il cloud resta la base imprescindibile per governare dati, complessità e lock-in in uno scenario sempre più orientato all’hybrid cloud
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 26-12-2009, 15:45   #1
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
[C++] Dubbi su costruttori, tipi di ritorno e union

Innanzitutto tanti auguri a tutti gli utenti del forum.
Sto seguendo questo tutorial: LINK
Tra ieri e l'altro ieri ho letto la parte relativa alle classi (parte I e II) e non ho capito alcune cose. Provo a fare una lista:

1. Come funziona una union usata come classe? Se ho ben capito i membri di tipo dato occupano tutti la stessa area di memoria, mentre le funzioni membro occupano uno spazio a parte (questo lo immagino io, nel tutorial non lo spiega). E' corretto?

2. A cosa serve usare un riferimento come tipo di ritorno di una funzione? Aggiungo più avanti un esempio che riassume questa e la prossima domanda.

3. Qual è il ciclo di vita di un oggetto in C++? Sono abituato al java in cui finchè esiste un riferimento all'oggetto questo non viene distrutto, qui invece se ho capito bene se l'oggetto è instanziato con new permane in memoria finchè non viene deallocato con delete, se invece è dichiarato come variabile locale permane solo nel blocco in cui è dichiarato.

I dubbi 2 e 3 mi sono venuti dopo aver letto questo esempio del tutorial:
Codice:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
    int x,y;
    CVector () {};
    CVector (int,int);
    CVector operator + (CVector);
    CVector& operator = (const CVector&);
};
CVector::CVector (int a, int b) {
    x = a;
    y = b;
}
CVector CVector::operator+ (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    return (temp);
}
CVector& CVector::operator= (const CVector& param) {
    x=param.x;
    y=param.y;
    return *this;
}
int main () {
    CVector a (3,1);
    CVector b (1,2);
    CVector c;
    c = a + b;
    cout << c.x << "," << c.y;
    return 0;
}
I motivi dei miei dubbi sono evidenziati in rosso. Nell'overloading dell'operatore + non so se è un errore aver restituito temp (che è una variabile locale) o no... E per quanto riguarda l'overloading dell'operatore =, che a detta del tutorial è forse equivalente all'implementazione offerta in automatico dal compilatore, non ho capito il valore di ritorno (perché finora il tutorial ha parlato di riferimento solo riguardo i parametri e non i tipi di ritorno).

4. Ho arricchito il codice sopra per tentare di capire alcune cose e questo è il risultato (che non capisco):
Codice:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
    static int n;
    int x,y;
    CVector () {
         n++;
        cout << "+" << endl;
    };
    CVector (int,int);
    ~CVector() {
        n--;
        cout << "-" << endl;
    };
    CVector operator + (CVector);
    //CVector& operator= (const CVector& param);
};

int CVector::n=0;

CVector::CVector (int a, int b) {
    n++;
    cout << "+" << endl;
    x = a;
    y = b;
}
CVector CVector::operator+ (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    cout << "operator+: " << CVector::n << endl;
    return (temp);
}

/*CVector& CVector::operator= (const CVector& param) {
    x=param.x;
    y=param.y;
    return *this;
}*/

int main () {
    CVector a (3,1);
    CVector b (1,2);
    CVector c;
    cout << "Dichiarazioni variabili locali: " << CVector::n << endl;
    c = a + b;
    cout << a.x << "," << a.y <<endl;
    cout << b.x << "," << b.y <<endl;
    cout << c.x << "," << c.y <<endl;

    cout << "Fine: " << CVector::n << endl;
    return 0;
}
E questo è l'output:
Codice:
+
+
+
Dichiarazioni variabili locali: 3
+
operator+: 4
-
-
3,1
1,2
4,3
Fine: 2
-
-
-

Process returned 0 (0x0)   execution time : 0.147 s
Press any key to continue.
Perché ci sono 4 "+" e 5 "-"? Perché alla fine risulta che siano allocati solo 2 oggetti? Come mai nonostante ciò è possibile stamparne 3? Cosa succede esattamente nell'assegnazione che ho evidenziato in rosso?

Sono molte domande quindi anche se mi rispondete poco per volta va bene. Grazie e ancora auguri!
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 14:25   #2
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Ho letto parte di un altro libro e ho trovato un po' di risposte...

Riguardo la 1 era corretto come immaginavo.

Sulla 2: Nel caso dell'assegnazione è utile per poter concatenare più assegnazioni, infatti prendono come parametro un riferimento, quindi l'unico modo è restituire un riferimento. Ho trovato casi in cui si restituiscono riferimenti solo in overload di operatori. Se avete modo di chiarire ulteriormente la questione le vostre informazioni sono ben accolte.

Riguardo la 4: ci sono 4 + e 5 - perché nell'overload dell'operatore + quando viene ritornato temp in realtà non viene ritornato temp stesso ma viene richiamato un costruttore automatico (che quindi crea un nuovo oggetto) di cui non ho fatto l'overload (si tratta della memberwise initialization se la mia fonte è corretta) e di conseguenza non viene stampato il + corrispondente. Per lo stesso motivo non viene incrementato n e quindi nelle stampe successive risulta che siano allocati 2 oggetti nonostante se ne possano stampare 3.

Sulla 3 invece ancora non ho capito bene... Quello che mi manda in confusione è il fatto che a volte le funzioni ritornino un oggetto, come nel punto 4, e in quel caso non ho capito quando l'oggetto viene distrutto: forse al termine del blocco che ha richiamato la funzione?

Ad ogni modo se ho sbagliato qualcosa correggetemi, ci tengo molto a capire bene tutto.
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 14:39   #3
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Ripensandoci il punto 4 ancora non torna...
Allora, nel main vengono creati 3 oggetti, poi nell'overload dell'operatore + (lo riporto qui)
Codice:
CVector CVector::operator+ (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    cout << "operator+: " << CVector::n << endl;
    return (temp);
}
param viene creato con una memberwise initialization e quindi non incrementa il contatore (però lo decrementa quando viene distrutto), temp viene creato e aggiunto a n. A questo punto la cout mi stampa 4 cioè i 3 oggetti del main più temp e fin qui tutto bene... Poi viene ritornato temp, quindi viene fatta un'altra memberwise initialization che non viene contata (quindi in questo momento abbiamo 6 oggetti allocati di cui 4 contati) e successivamente vengono distrutti param e temp e di qui l'output di 2 "-" (e n viene decrementato di 2, quindi vale 2).
Ora viene richiamata la funzione = che non distrugge c ma gli assegna gli stessi valori dell'oggetto che è stato ritornato dalla funzione + (è proprio lo stesso oggetto perché stavolta param è passato per riferimento).
Quindi si ritorna nel main dove vengono stampati i 3 oggetti e viene stampato n che giustamente vale 2. Ma di oggetti in memoria al momento dovrei averne 4: a,b,c e la copia di temp che era stata ritornata dalla funzione +. Quindi perché alla fine vengono richiamati solo 3 distruttori (i 3 "-" finali)?
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 15:01   #4
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Ho fatto un'altra prova, ho sovrascritto il costruttore automatico di inizializzazione, ecco il codice e l'output:
Codice:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
    static int n;
    int x,y;
    CVector () {
         n++;
        cout << "+" << endl;
    };
    CVector (const CVector &cv) : x(cv.x),y(cv.y){
        n++;
        cout << "Memberwise initialization" << endl;
        cout << "+" << endl;
    }
    CVector (int,int);
    ~CVector() {
        n--;
        cout << "-" << endl;
    };
    CVector operator + (CVector);
    CVector& operator= (const CVector& param);
};

int CVector::n=0;

CVector::CVector (int a, int b) {
    n++;
    cout << "+" << endl;
    x = a;
    y = b;
}
CVector CVector::operator+ (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    cout << "operator+: " << CVector::n << endl;
    return (temp);
}

CVector& CVector::operator= (const CVector& param) {
    x=param.x;
    y=param.y;
    cout << "operator=: " << CVector::n << endl;
    return *this;
}

int main () {
    CVector a (3,1);
    CVector b (1,2);
    CVector c;
    cout << "Dichiarazioni variabili locali: " << CVector::n << endl;
    c = a + b;
    cout << a.x << "," << a.y <<endl;
    cout << b.x << "," << b.y <<endl;
    cout << c.x << "," << c.y <<endl;

    cout << "Fine: " << CVector::n << endl;
    return 0;
}
Codice:
+
+
+
Dichiarazioni variabili locali: 3
Memberwise initialization
+
+
operator+: 5
operator=: 5
-
-
3,1
1,2
4,3
Fine: 3
-
-
-

Process returned 0 (0x0)   execution time : 0.103 s
Press any key to continue.
Evidentemente i conti che ho fatto nel post precedente sono sbagliati: intanto c'è solo una memberwise initialization e penso sia quella di param (quello della funzione +), poi param e temp vengono distrutti dopo la chiamata alla funzione = e non alla fine della funzione + (non è strano?)... E infine cos'è che restituisce la funzione +? temp, una sua copia o cos'altro?
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 15:21   #5
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Ho scritto un codice ancora più completo. Eccolo, con l'output:
Codice:
// vectors: overloading operators example
#include <iostream>
using namespace std;
class CVector {
public:
    static int n;
    static int tot;
    int x,y,id;
    CVector () : id(tot) {
        tot++;
        n++;
        cout << "id: " << id << " +" << endl;
    };
    CVector (const CVector &cv) : x(cv.x),y(cv.y),id(tot){
        tot++;
        n++;
        cout << "Memberwise initialization" << endl;
        cout << "id: " << id << " +\tx: " << x << " y: " << y << endl;
    }
    CVector (int,int);
    ~CVector() {
        n--;
        cout << "id: " << id << " -\tx: " << x << " y: " << y << endl;
    };
    CVector operator + (CVector);
    CVector& operator= (const CVector& param);
};

int CVector::n=0;
int CVector::tot=0;

CVector::CVector (int a, int b) : x(a),y(b),id(tot) {
    tot++;
    n++;
    cout << "id: " << id << " +\tx: " << x << " y: " << y << endl;
}
CVector CVector::operator+ (CVector param) {
    CVector temp;
    temp.x = x + param.x;
    temp.y = y + param.y;
    cout << "operator+: " << CVector::n << endl;
    return (temp);
}

CVector& CVector::operator= (const CVector& param) {
    x=param.x;
    y=param.y;
    cout << "operator=: " << CVector::n << endl;
    return *this;
}

int main () {
    CVector a (3,1);
    CVector b (1,2);
    CVector c;
    cout << "Dichiarazioni variabili locali: " << CVector::n << endl;
    c = a + b;
    cout << a.x << "," << a.y <<endl;
    cout << b.x << "," << b.y <<endl;
    cout << c.x << "," << c.y <<endl;

    cout << "Fine: " << CVector::n << endl;
    return 0;
}
Codice:
id: 0 + x: 3 y: 1
id: 1 + x: 1 y: 2
id: 2 +
Dichiarazioni variabili locali: 3
Memberwise initialization
id: 3 + x: 1 y: 2
id: 4 +
operator+: 5
operator=: 5
id: 4 - x: 4 y: 3
id: 3 - x: 1 y: 2
3,1
1,2
4,3
Fine: 3
id: 2 - x: 4 y: 3
id: 1 - x: 1 y: 2
id: 0 - x: 3 y: 1

Process returned 0 (0x0)   execution time : 0.029 s
Press any key to continue.
Ho aggiunto un id ad ogni oggetto e al momento della costruzione e della distruzione stampo x e y per capire meglio chi viene costruito/distrutto...
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 27-12-2009, 19:01   #6
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Dopo ulteriori test e ricerche su internet credo di aver capito tutto, sono giunto a due conclusioni:
- Il fatto che nella funzione + temp non venga ricopiato in un oggetto di ritorno automatico e quindi non venga richiamato il costruttore di inizializzazione di default è dovuto ad un'ottimizzazione del compilatore: invece di creare inutilmente due oggetti usa direttamente temp come se fosse l'oggetto di ritorno.
- Quando una funzione torna un oggetto questo viene utilizzato nell'operazione/funzione/qualsiasicosa in cui la chiamata era contenuta e poi viene distrutto. Penso che la distruzione del parametro/parametri venga effettuata insieme per ragioni di ottimizzazione.

Spero che questo thread possa essere utile a tutti. Se ho scritto cose sbagliate spero che mi correggerete.
wingman87 è offline   Rispondi citando il messaggio o parte di esso
Old 28-12-2009, 00:12   #7
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da wingman87 Guarda i messaggi
Sulla 3 invece ancora non ho capito bene... Quello che mi manda in confusione è il fatto che a volte le funzioni ritornino un oggetto, come nel punto 4, e in quel caso non ho capito quando l'oggetto viene distrutto: forse al termine del blocco che ha richiamato la funzione?

Ad ogni modo se ho sbagliato qualcosa correggetemi, ci tengo molto a capire bene tutto.
Calma che secondo me stai facendo un pò troppa confusione.
Per prima cosa non sono funzioni ma metodi.
Nel caso di passaggio per copia l'oggetto viene distrutto al termine dell'istruzione che ha invocato il metodo.
Se ritorni un riferimento ovviamente non puoi ritornare un oggetto locale perchè questo verrebbe distrutto al momento dell'uscita dal metodo, con il risultato di avere un riferimento non valido.
Per questo l'operatore + ritorna una copia dell'oggetto temp definito localmente, al contrario l'operatore di assegnamento ritornando un *this può ritornare un riferimento in quanto this ha uno scope maggiore rispetto all'istruzione di assegnamento.
Nel futuro standard è stata definita la move semantics e gli rvalue reference identificati dalla sintassi && per cui puoi ritornare un riferimento ad una variabile locale.

Secondo me però hai sbagliato l'operatore +. Hai ridefinito l'operatore unario + (per intendersi l'operatore segno positivo), non l'operatore somma. L'operatore somma prende 2 oggetti di tipo CVector e ritorna un nuovo oggetto CVector.

Ed eventualmente l'operatore unario doveva avere questa firma:
Codice:
CVector CVector::operator+ (const CVector & param)
Inutile e deleterio passare param come copia.
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 28-12-2009, 03:08   #8
wingman87
Senior Member
 
Iscritto dal: Nov 2005
Messaggi: 2782
Grazie mille per la risposta.
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Calma che secondo me stai facendo un pò troppa confusione.
Per prima cosa non sono funzioni ma metodi.
Nel caso di passaggio per copia l'oggetto viene distrutto al termine dell'istruzione che ha invocato il metodo.
Se ritorni un riferimento ovviamente non puoi ritornare un oggetto locale perchè questo verrebbe distrutto al momento dell'uscita dal metodo, con il risultato di avere un riferimento non valido.
Per "ritornare un riferimento" intendi ritornare un puntatore o un riferimento tipo come si fa nell'overload dell'operatore =?
Codice:
CVector& CVector::operator= (const CVector& param);
Quote:
Per questo l'operatore + ritorna una copia dell'oggetto temp definito localmente, al contrario l'operatore di assegnamento ritornando un *this può ritornare un riferimento in quanto this ha uno scope maggiore rispetto all'istruzione di assegnamento.
Però non ho capito quando l'oggetto ritornato dall'operatore + viene distrutto. Basandomi sulle prove che ho fatto sembrerebbe che viene distrutto al termine della istruzione che conteneva la chiamata al metodo, insieme ai parametri passati per copia.
Quote:
Nel futuro standard è stata definita la move semantics e gli rvalue reference identificati dalla sintassi && per cui puoi ritornare un riferimento ad una variabile locale.
Quindi in questo caso la variabile locale non verrebbe distrutta al termine della chiamata del metodo?
Quote:
Secondo me però hai sbagliato l'operatore +. Hai ridefinito l'operatore unario + (per intendersi l'operatore segno positivo), non l'operatore somma. L'operatore somma prende 2 oggetti di tipo CVector e ritorna un nuovo oggetto CVector.

Ed eventualmente l'operatore unario doveva avere questa firma:
Codice:
CVector CVector::operator+ (const CVector & param)
Inutile e deleterio passare param come copia.
In verità così come ne ho fatto l'overload sembra funzionare correttamente, e mi sembra anche logicamente corretto. I parametri sono in realtà due perché uno è implicito, è l'oggetto *this.
wingman87 è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Recensione vivo X300 Pro: è ancora lui il re della fotografia mobile, peccato per la batteria Recensione vivo X300 Pro: è ancora lui il...
Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'' per spingere gli handheld gaming PC al massimo Lenovo Legion Go 2: Ryzen Z2 Extreme e OLED 8,8'...
AWS re:Invent 2025: inizia l'era dell'AI-as-a-Service con al centro gli agenti AWS re:Invent 2025: inizia l'era dell'AI-as-a-Se...
Cos'è la bolla dell'IA e perché se ne parla Cos'è la bolla dell'IA e perché se...
BOOX Palma 2 Pro in prova: l'e-reader diventa a colori, e davvero tascabile BOOX Palma 2 Pro in prova: l'e-reader diventa a ...
Alcuni rivenditori giapponesi bloccano l...
Le feste non placano Amazon, anzi: aggio...
Roborock Q10 S5+ a un super prezzo: robo...
Formula sceglie WINDTRE BUSINESS per gar...
EXPO 1.20: AMD migliora il supporto all'...
MacBook Pro con chip M4, 24GB di RAM e 1...
Lefant M330 da 6.000Pa a 139€ o ECOVACS ...
Tornano gli sconti anche sulle scope ele...
Le scope elettriche Dreame H12, H14 e H1...
Il nucleo della cometa interstellare 3I/...
La Russia potrebbe sviluppare un'arma pe...
Manda la RAM Corsair in assistenza, rice...
ASUS ROG G1000 con 'AniMe Holo': saranno...
Un test di longevità ha messo alla prova...
Incat inizia i test dell'incredibile tra...
Chromium
GPU-Z
OCCT
LibreOffice Portable
Opera One Portable
Opera One 106
CCleaner Portable
CCleaner Standard
Cpu-Z
Driver NVIDIA GeForce 546.65 WHQL
SmartFTP
Trillian
Google Chrome Portable
Google Chrome 120
VirtualBox
Tutti gli articoli Tutte le news Tutti i download

Strumenti

Regole
Non Puoi aprire nuove discussioni
Non Puoi rispondere ai messaggi
Non Puoi allegare file
Non Puoi modificare i tuoi messaggi

Il codice vB è On
Le Faccine sono On
Il codice [IMG] è On
Il codice HTML è Off
Vai al Forum


Tutti gli orari sono GMT +1. Ora sono le: 11:32.


Powered by vBulletin® Version 3.6.4
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Served by www3v