Newsgroup: it.comp.lang.c++
Titolo: Ritornare references

Ho qualche problemino a capire bene come usare i reference in C++.
Ora in C avrei la seguente cosa +/-
--8<---------------cut here---------------start------------->8---
main {
     res = malloc(sizeof(type));
     doSomething(res);
}
void doSomething(type *pointer) {
     // put something in pointer
}
--8<---------------cut here---------------end--------------->8---
In C++ questo non è necessario, ma mi par di capire che dovrei fare
--8<---------------cut here---------------start------------->8---
main {
     res = doSomething();
}
type& doSomething() {
      // create a new object and return it
}
--8<---------------cut here---------------end--------------->8---
ma
1. questo non dovrebbe essere un oggetto locale alla funzione?
2. non ho un memory leak?
Leggendo 
http://www.parashift.com/c++-faq/index.html
poi ho visto che al contrario di ciò che pensavo, ritornare un oggetto
invece del reference/pointer è più efficiente, dato che in realtà il
compiliatore è abbastanza intelligente da non copiare.
Allora forse non conviene tornare sempre per valore?
Grazie..

 Allora forse non conviene tornare sempre per valore?
No. Di regola conviene ritornare per valore oggetti la cui copia non 
richiede allocazioni di memoria. Per esempio, conviene ritornare per 
valore numeri o strutture contenenti solo una manciata di numeri, ma non 
conviene ritornare per valore collezioni o stringhe.
Il compilatore e' abbastanza intelligente da non copiare l'oggetto 
ritornato se questo viene creato nella stessa istruzione di return, 
altrimenti, non e' garantita l'ottimizzazione. Vedi:
http://en.wikipedia.org/wiki/Return_value_optimization
--
Carlo Milanesi

 Carlo Milanesi
Ok certo ha senso, non si può fare troppo affidamento su compilatori
ultraintelligenti.
Grazie

Quindi per esempio questa cosa stupidissima avrebbe senso?
--8<---------------cut here---------------start------------->8---
#include <vector>
#include <iostream>
#include <cstdlib>
void create_vector(int a, int b, std::vector<int>& vec) {
    vec[0] = a;
    vec[1] = b;
}
int main() {
    std::vector<int> v(2);
    create_vector(1, 10, v);
    for (int i = 0; i < v.size(); ++i) {
        std::cout << "value at " << i << " == " << v[i] << std::endl;
    }
    return 0;
}
--8<---------------cut here---------------end--------------->8---
Non vedo altrimenti come allocare memoria all'interno di create_vector
avendo poi la certezza di liberarla al di fuori di essa...

E a proposito è normale che in C++ pur non avendo chiamato nessuna new
controllando con valgrind questo stupido programma
--8<---------------cut here---------------start------------->8---
void create_vector(int a, int b, int_vec_t& vec) {
    vec.push_back(a);
    vec.push_back(b);
}
void print_vector(int_vec_t& vec) {
    for (int i=0; i < vec.size(); ++i) {
        printf("at position %d we have %d\n", i, vec[i]);
    }
}
int main() {
    int_vec_t v;
    create_vector(12, 10, v);
    print_vector(v);
    std::vector<int>::const_iterator i;
    // using an iterator on the vector
    // iterators are a generalization of pointers in C++
    for (i=v.begin(); i!=v.end(); ++i) {
        std::cout << (*i) << std::endl;
    }
    sort(v.begin(), v.end());
    print_vector(v);
    return 0;
}
--8<---------------cut here---------------end--------------->8---
Ho della memoria non liberata prima della chiusura?
--8<---------------cut here---------------start------------->8---
==7420== Memcheck, a memory error detector
==7420== Copyright (C) 2002-2010, and GNU GPL'd, by Julian Seward et al.
==7420== Using Valgrind-3.6.0.SVN and LibVEX; rerun with -h for copyright info
==7420== Command: ./a.out -v
==7420== 
--7420-- ./a.out:
--7420-- dSYM directory has wrong UUID; consider using --dsymutil=yes
at position 0 we have 12
at position 1 we have 10
12
10
at position 0 we have 10
at position 1 we have 12
==7420== 
==7420== HEAP SUMMARY:
==7420==     in use at exit: 4,184 bytes in 2 blocks
==7420==   total heap usage: 4 allocs, 2 frees, 4,196 bytes allocated
==7420== 
--8<---------------cut here---------------end--------------->8---

 fare le cose, mi basta capire qual è quello giusto in C++...
Se in C++ ci sono molti modi di fare le cose, e' principalmente per due 
motivi: per mantenere la compatibilita' con il C, e per consentire 
tecniche avanzate, flessibili, ed efficienti di programmazione. 
Probabilmente e' il linguaggio di programmazione piu' difficile, e 
infatti il numero di programmatori che lo usa sta lentamente diminuendo.
--
Carlo Milanesi

 oppure per riferimento o per riferimento a const
Come sopra, un temporaneo può essere passato solo per valore o per 
riferimento a const, non per riferimento non-const.
Ciao.

 lentamente diminuendo.
Sì sicuramente non è semplice, anche se devo dire che ne apprezzo molto
la sua flessibilità...

 Carlo Milanesi


Beh ne conosco qualcuno e i linguaggi funzionali una volta capito come
funzionano veramente sono mille volte più semplici del C++ secondo me.
Le uniche cose che è trovato più faticose sono le monadi in Haskell...
Poi ovviamente dipende dall'ambito, in alcuni domini sono naturali in
altri si fa più fatica...


Pardon. Ecco allora un programma completo e corretto:
   typedef double type;
   void doSomething(type& riferimento) { }
   int main() {
     type a;
     doSomething(a);
   }
--
Carlo Milanesi