Newsgroup: it.comp.lang.c++
Titolo: Conportamento ambiguo dell'eseguibile

Salve ragazzi,
mi potreste confermare cosa vi dà come output il seguente codice:
      int* puntatore = new int(5);
      cout << "valore contenuto nel puntatore" << " " << *puntatore <<
endl;
      cout << "indirizzo contenuto in puntatore" << " " << puntatore <<
endl;
      delete puntatore;
      cout << "indirizzo contenuto in puntatore" << " " << puntatore <<
endl;
      cout << "valore contenuto nel puntatore " << " " << *puntatore <<
endl;
I risultati sono che per quanto abbia distrutto la variabile intera creata
in memoria ed il rispettivo indirizzo assegnato al puntatore, è come se
niente fosse avvenuto:
valore contenuto nel puntatore   5
indirizzo contenuto nel puntatore 0X34144433
indirizzo contenuto nel puntatore 0X34144433
valore contenuto nel puntatore 5
Per finire ci vuole la "ciliegina sulla torta": ovverro aggiungete le
seguenti righe:
      int* puntatore2 = puntatore;
     cout << "valore del secondo puntatore" << " " << *puntatore2 << endl;
     cout << "valore contenuto nel puntatore2" << " " << puntatore2 <<
endl;
Output:
OX34144433
5
Secondo voi da che cosa dipende? Forse dal tipo di indirizzamento fatto dal
compilatore?
Grazie.
-- 
La classifica dei prodotti MS:
C#, la migliore barzelletta di Bill Gates.
Visual C++, il meno standard dei compilatori C++.
J++, la copiatura più riuscita.
Windows, il più instabile.
Visual Basic, un esempio di prodotto decente della MS - forse l'unico -.
OutlookExpress, scandali su scandali.
La classifica degli "amici" coglioni:
Stefano Zanchi, il miglior lamer del mondo.
 

 compilatore?
In breve: quando si esegue new su un puntatore, gli si assegna una zona di
memoria diversa dalla locazione 0 (nel tuo caso 0x34144433), che e' il punto
d'inizio della memoria ove verra' allocata la variabile. Se poi distruggo
tale zona con delete, non faccio altro che contrassegnarla come disponibile,
ma non la azzero. Questo perché non avrebbe senso azzerare un blocco di
memoria che non si utilizza più, e anche perché ne risulterebbe una
diminuzione delle prestazioni, cosa che il C++ non vuole affatto. Quando si
riutilizzerà il blocco per una nuova variabile, allora si provvederà
all'azzeramento (meglio dire "inizializzazione").
C'è da aggiungere che il comportamento del tuo programma non è affatto
strano: il puntatore punta sempre alla zona di memoria nella quale new aveva
allocato, anche dopo delete. L'assegnamento di tale puntatore ad un altro
dello stesso tipo è sempre valido. La dereferenziazione di un puntatore che
punta a memoria non allocata dà comportamento indefinito (nel tuo caso, come
nella maggior parte, lascia tranquillamente vedere la variabile
precedentemente allocata). Prova invece a scrivere nella zona di memoria
deallocata: avrai quasi certamente una Segmentation Fault, a meno che non ti
trovi nel vecchio DOS in modalità non protetta.
Ciao
Domenico Barra

 compilatore?
#include <imho>
la memoria viene effettivamente liberata dopo la chiamata a delete; il
puntatore punta quindi ad un'area non assegnata ma che contiente ancora
il vecchio valore solo perche` non e` ancora stata sovrascritta
prova ad eseguire:
int* puntatore = new int(5);
cout << "valore contenuto nel puntatore" << " " <<*puntatore << endl;
cout << "indirizzo contenuto in puntatore" << " " <<puntatore << endl;
delete puntatore;
int *p = new int(10);
cout << "indirizzo contenuto in puntatore" << " " << puntatore << endl;
cout << "valore contenuto nel puntatore " << " " << *puntatore << endl;
delete p;
sul mio sistema l'output e`:
valore contenuto nel puntatore 5
indirizzo contenuto in puntatore 0x8049e38
indirizzo contenuto in puntatore 0x8049e38
valore contenuto nel puntatore  10
ma tieni presente che e` una cosa casuale
il programma gira perche` i puntatori sono dello stesso tipo e non e`
stata eseguita alcuna allocazione di memoria fra delete puntatore e 
int *p = new int(10)
ma come ho gia` detto e` una cosa casuale; accedendo ad un area di
memoria non allocata il comportamento e` _indefinito_: quindi potresti
avere un risultato corretto, un risultato inatteso o un seg_fault
ciao
Kronos
-- 
Home: 
http://kronoz.tsx.org
Software is like sex; it's better when it's free.
Linus Torvalds

 trovi nel vecchio DOS in modalita` non protetta.
kronos:/tmp$ cat p.cpp
#include <iostream>
int main () {
        int* puntatore = new int(5);
        cout <<"valore contenuto nel puntatore" <<" "<<*puntatore <<endl;
        cout <<"indirizzo contenuto in puntatore" <<" "<<puntatore <<endl;
        delete puntatore;
        *puntatore=15;
        cout<<"indirizzo contenuto in puntatore"<<" "<< puntatore<<endl;
        cout<<"valore contenuto nel puntatore " <<" "<< *puntatore<<endl;
}
kronos:/tmp$ g++ -op -Wall p.cpp
kronos:/tmp$ ./t
valore contenuto nel puntatore 5
indirizzo contenuto in puntatore 0x8049e58
indirizzo contenuto in puntatore 0x8049e58
valore contenuto nel puntatore  15
mmmmh, dov'e` la fregatura?
la lettura di un'area di memoria non allocata ha un risultato
indefinito, ok fin qui ci sono...
ma io qui sto *scrivendo* in un'area non allocata, perche` qualcosa
(l'OS?) non me lo impedisce?
lo standard si pronuncia in merito a questa cosa?
ciao
Kronos
-- 
Home: 
http://kronoz.tsx.org
Reply-To: 
kro...@myself.com
Non ho ancora capito se il mio cane e' maschio o femmina:
quando fa la pipi' si chiude in bagno

 (l'OS?) non me lo impedisce?
Perché se il puntatore contiene un indirizzo compreso in qualche segmento
del tuo programma, non si capisce proprio perché dovrebbe impedirtelo :-)
Ma se (ad esempio) puntasse ad un'area di memoria appartenente a un altro
processo, o addirittura all'OS, allora sentiresti un bel botto ;-)
Massimo

Ringrazio tutti per le risposte.
Cmq mi rimane un interrogativo riguardo a delete: quando avevo imparato
come operava veniva anche detto che assegnava NULL al puntatore stesso.
Quindi voi mi confermate che non č vero?
Ciao.
-- 
La classifica dei prodotti MS:
C#, la migliore barzelletta di Bill Gates.
Visual C++, il meno standard dei compilatori C++.
J++, la copiatura piů riuscita.
Windows, il piů instabile.


Quindi voi mi confermate che non è vero?
No... pero' e' buona regola evitare di lasciare in giro puntatori
a cose che non esistono piu' (dangling pointers). Spesso nel codice
si scrivono cose come:
    delete my_inst; my_inst=0;
Un caso in cui non si fa e' quando il puntatore verrebbe comunque
distrutto immediatamente dopo... es:
   String::~String()
   {
     delete chars;
   }
HTH
Andrea
--
Andrea Griffini, Programmer
http://www.netservers.com/~agriff

lo standard si pronuncia in merito a questa cosa?
Questa e' una cosa che mi capita spesso di leggere qui nel newsgroup
e che mi preoccupa un poco. Secondo me ci si dimentica che il C++ e'
un linguaggio di alto livello che pero' arriva sino al metallo...
Quando si sconfina o si accede a memoria dopo averla deallocata (o
si usano iterator invalidati o mille altre cose ancora) si entra nel
territorio denominato "undefined behaviour" che purtroppo molti
associano a "general protection fault" oppure a "segmentation fault"
o "bus error" ...
"undefined behaviour" e' molto peggio... se sei *fortunatissimo*
allora immediatamente di capita un bel GPF. Nei casi standard ti
capita un GPF solo molto tempo dopo che la marachella e' stata
commessa e in un punto del codice totalmente scorrelato e
assolutamente corretto (e questo lo paghi con ore e ore e ore di
debug... spesso arrivando a incolpare un innocente compilatore o
colleghi che ti hanno fatto il malocchio).
Se sei molto sfortunato il codice girera' senza problemi apparenti
e con la sola conseguenza di archiviare i dati del paziente
scombinando l'elenco delle allergie specifice. E in questo caso
qualcuno ci rimarra' addirittura secco.
Una frase citata spesso e' che "undefined behaviour" potrebbe far
uscire dei demoni dal naso del programmatore senza essere in
violazione con lo standard... purtroppo accade spesso che le
conseguenze siano molto meno evidenti e ben piu' subdole.
scrivere
    int x[10];
    x[1000]++;
potrebbe:
   1) generare un bel crash
   2) far crashare la prossima chiamata a sort
      anche se quella viene fatta su altri dati e
      con parametri corretti
   3) formattare il disco fisso
   4) mandare una email di insulti al mio capo
   5) fare uscire un demone dal mio naso
   6) (cosa piu' grave e molto frequente) non fare
      assolutamente nulla di visibile


Come giustamente detto, utilizzare un puntatore non inizializzato o un
puntatore a oggetti rilasciati da delete, secondo lo standard, da
risultato indefinito. 
Andrebbe ricordata la differenza fra "indefinito" e "definito dal
compilatore". Indefinito significa che il compilatore non è tenuto a
documentare cosa fa e neppure a fare qualcosa di sensato. Potrebbe anche
fare cose diverse a seconda della fase lunare. I demoni dal naso sono
giustamente compresi. Inoltre un codice sintatticamente corretto ma che
da adito a comportamenti indefiniti a runtime non è conforme allo
standard. In altre parole, per quanto riguarda lo standard C++ quel
codice non è C++ errato, non è neppure C++.
Non so dove tu lo abbia studiato, ma il delete NON modifica
assolutamente il puntatore relativo (che potrebbe non esistere). E te ne
accorgi anche solo guardando il prototipo di operator delete che accetta
un l-value e non un r-value.
Quindi, a meno che non lo faccia tu esplicitamente, un puntatore non
viene inizializzato ne resettato a NULL da delete.
Domande più utili su new e delete spinti ai casi limite, e che ti lascio
come esercizio di studio, sono le seguenti:
int *p1 = NULL;
delete p1;
p1 = new int[0];
class MyClass {}; // sizeof(MyClass) == 0
MyClass *pMyClass = NULL;
pMyClass = new MyClass;
pMyClass = new MyClass[2];
-- 
Posted from 
adsl-21-135.38-151.net24.it
 [151.38.135.21] 
via Mailgate.ORG Server - 
http://www.Mailgate.ORG

pMyClass = new MyClass[2];
...all'anima dell'esercizio, questa è roba da collasso cardiaco immediato
:-)))
Seriamente, non riesco a spiegarmi il comportamento di nemmeno una di queste
istruzioni...
Massimo

istruzioni...
Come spiegavo nell'altro post, è molto che sto lontano dal C++.
Ecco perchè lo lasciavo come esercizio ;)
Comunque:
domanda: come opera delete se gli viene passato NULL (ovviamente
castato correttamente?).
risposta: non me lo ricordo! Sig! Credo comunque sia scorretto. 
Ovvero dovrebbe generare una eccezione oppure avere undefined 
behaviour.
domanda: come opera free(0)? Risposta. Non ne sono sicuro ma credo
che il C non dica nulla mentre il C++ esplicita che lo accetta e 
non fa nulla.
domanda: come ci si comporta per un'allocazione di array di zero
elementi? 
risposta: non mi ricordo. C'e' da notare che oltre al caso new T[0]
esiste anche il caso malloc(0) e che questo secondo può differire
fra C e C++. Ricordo che in almeno un caso (ma quale??) la risposta
era: ritorna un valore diverso da NULL, univoco e gestibile da 
(delete o free a seconda del caso, ed eventualmente anche realloc) 
ma che non deve essere altrimenti dereferenziato (pena undefined
behaviour).
domanda: come ci si comporta con un tipo T per cui sizeof(T)==0 ?
risposta: questo sono sicuro. Il tipo T è valido e funziona. T a; 
esiste e &a è un indirizzo. T v[n]; dove n è una costante intera 
compatibile con size_t esiste ed è un array valido. Non solo, 
&v[0]+1==&v[1] è vera e &v[0]<&v[1] è vera (ovvero sono due 
indirizzi diversi). Ovviamente anche l'allocazione dinamica 
funziona. Quello che NON ricordo è se sizeof(T) resta a zero o 
se diventa equivalente alla differenza 
	static_cast<size_t>(p+1)-static_cast<size_t>(p)
per una qualche T*p; pertanto dato "struct T{};" sizeof(T) non è 0. 


behaviour).
Ma quello non era il puntatore a void (pienamente utilizzabile, allocabile,
deallocabile, ma non dereferenziabile) ?
Massimo

deallocabile, ma non dereferenziabile) ?
puntatore a void e' un tipo, io parlavo di un valore di ritorno. 
Quando dico univoco intendo che se esegui la chiamata due volte
ti ritorna valori diversi. E non è affatto pienamente utilizzabile,
è utilizzabile solo nel contesto delle funzioni correlate.


elementi?
Se con new[1] comunichi di allocare una variabile in memoria di N byte, con
new[0] non allochi alcunché. Semplicemente lo new restituisce l'indirizzo
di memoria di tale locazione anche se abbiamo seguito un metodo illogico. 
Ciao.


di memoria di tale locazione anche se abbiamo seguito un metodo
illogico. 
Sembra facile, ma la logica dice che il costruttore non deve essere
eseguito
e che il valore ritornato non deve essere 0 e deve essere possibile
passarlo
a delete. Solo che con il delete non si deve eseguire il distruttore, il
che
non è banale dato che questo viene eseguito PRIMA di entrare in operator
delete.


      assolutamente nulla di visibile
Uno degli effetti reali più dannosi e meno percettibili di un errore
simile é quando il compilatore accede alle locazioni di memoria di
altre variabili modificando il loro valore. In questo caso si
potrebbero verificare malfunzionamenti in qualsiasi parte del
programma rendendo spesso difficile individuare il punto esatto dove é
avvenuto l'errore.
Lavinia
WINWORD.EXE - ERRORE DI APPLICAZIONE
l'istruzione a "0x3017ff27"ha fatto riferimento alla
memoria a "0x02a3143c".La memoria non poteva essere 'read'.

di memoria di tale locazione anche se abbiamo seguito un metodo illogico. 
Una allocazione di zero byte *deve* tornare un puntatore diverso dal
puntatore nullo e questo puntatore deve poter essere accettato da
operator delete. 
      void *p=operator new(0);
      if (p==0)
      {
        // Di qui non passa mai... se l'allocazione di zero
        // byte e' riuscita il puntatore e' comunque diverso
        // dal puntatore nullo. Se non e' riuscita allora
        // operator new ha lanciato una exception e di qui
        // non si passa comunque...
        ...
      }
HTH


in operator delete.
Non capisco di cosa state parlando... se scrivo
   int *v=new int[0];
ho allocato un array dinamico di zero elementi che pero' non
richiede zero byte di memoria (il compilatore C++ deve pur
memorizzare da qualche parte che il numero di elementi era zero
altrimenti delete[] non puo' sapere quandi distruttori chiamare).
Diverso e' se scrivo:
   void *o=operator new[](0);
In questo caso ho richiesto a "operator new[]" zero byte di
memoria e lo standard richiede che mi venga restituito un
puntatore diverso dal puntatore nullo. Questo puntatore deve
funzionare correttamente quando passato a operator delete[].
Qui pero' stiamo parlando di raw memory e non di oggetti e
quindi non ha senso tirare in ballo i distruttori.
Quando eseguo "delete p" o "delete[] p" dove p e' un puntatore
nullo il compilatore non fa nulla: non chiama nessun distruttore
e nessuna funzione di deallocazione memoria: il test sul
puntatore nullo viene fatto a monte.


domanda: come ci si comporta con un tipo T per cui sizeof(T)=3D=3D0 ?
Questa e' una parte abbastanza contorta (a mio parere). A quello
che ho capito sizeof() applicato ad una classe senza membri non puo'
essere inferiore ad 1. Sull'ultimo draft e' pero' ammesso che un
sub-oggetto base senza membri abbia pero' dimensione zero;
se ho capito correttamente la cosa ad esempio:
  class empty  { };
  class empty2 { };
  class derived : empty { };
  class contains { empty e1,e2,e3,e4; };
  class multiderived : empty,empty2 {};
sizeof(empty) > 0
  (quanto esattamente dipende dall'implementazione)
sizeof(derived) >= sizeof(empty)
  (non e' cioe' detto che sia maggiore)
sizeof(contains) >= 4*sizeof(empty)
  (sizeof di un aggregato non e' inferiore alla somma
   delle dimensioni degli elementi)
sizeof(multiderived) >= sizeof(empty)
  (le singole *basi* potrebbero avere dimensione zero in questo
   caso particolare: e' una regola speciale per i sotto-oggetti
   base)
Una cosa garantita e' che un array di N elementi T occupa sempre
N*sizeof(T) (ma un array dinamico di N elementi T richiedera'
invece qualche byte in piu' a operator new[] per la sua
allocazione).


 tentasse di deallocarlo (inizializzato o meno).
Quindi dici che viene comunque effettuato un if nella free()? Mi sembra
che ciò andrebbe contro la normale filosofia della massima efficienza
del C/C++, o sbaglio?
EMG

Ringrazio Andrea Griffini per le sue delicidazioni.
Come già ribadito sosno stato qualche anno lontano dal C++ e
con il tempo certi particolari si dimenticano. Inoltre non 
trovo più il testo che avevo (uno degli ultimi draft dello 
standard). Andrea, hai per caso uno degli ultimi draft in
formato elettronico? Di quelli che erano "pubblici" prima
della versione "definitiva" (ma è mai definitivo uno standard
di linguaggio?) che non è pubblica ma va acquistata?
Vorrei ricapitolare i casi limite relativi alle 
allocazioni/deallocazioni, e chiedo ad Andrea di 
confermare/smentire quello che mi sembra sia saltato fuori 
in questo thread (unito a quello che ricordo):
1) Allocazione di raw memory, lunghezza zero.
1.a) Caso malloc e fratelli in C: forse è come in C++, qualcuno
può verificare?
1.b) Caso malloc e fratelli in C++: ritorna un puntatore valido 
e non nullo. Derereferenziarlo ha comportamento indefinito. Va 
passato a free come un qualunque puntatore dinamico di questo 
tipo. Può essere passato a realloc come un qualunque puntatore 
dinamico di questo tipo.
1.c) Caso new/new[] in C++: ritorna un puntatore valido e non 
nullo. Derereferenziarlo ha comportamento indefinito. Va passato 
a delete/delete[] come un qualunque puntatore dinamico di questo 
tipo. 
2) Allocazione di vettori di 0 elementi.
Ovviamente questo può essere fatto solo in C++ con new[]. Ritorna 
un puntatore valido e non nullo. Derereferenziarlo ha comportamento
indefinito (infatti gli elementi sono 0!). Va passato a delete[] 
come un qualunque puntatore dinamico di questo tipo. 
3) Deallocazione/reallocazione di NULL/0.
3.a) Caso free in C: forse è come in C++, qualcuno può verificare?
3.b) Caso realloc in C: non ne ho idea! Qualcuno può verificare?
3.c) Caso free C++: non ne sono sicuro. Credo semplicemente
che lo ignori senza dare errori. Andrea puoi verificare?
3.d) Caso realloc in C++: non ne ho idea! Andrea puoi verificare?
3.e) Caso delete/delete[] in C++: viene ignorato e non da alcun
errore. E' un'operazione valida.
3) Strutture senza elementi.
Una struttura senza elementi (o con solo metodi non virtuali).
NON ha sizeof zero. Però se inserita all'interno di un'altra
struttura (o se ereditata) può non aumentare la dimensione della
nuova struttura. Almeno in C++, in C non sono sicuro.
Piccola postilla sulla diartiba NULL/0 e zero-bits.
Sua in C che in C++ un puntatore può essere valido o non valido.
Inoltre un puntatore valido può essere nullo o meno.
Vi è differenza fra un puntatore e un indirizzo, sono due cose 
diverse. E sono anche diverse dal valore ottenuto castando
il puntatore ad un intero.
In C il valore di un puntatore nullo è rappresentato dalla 
macro/costante predefinita NULL. In c++ è rappresentato dalla
costante intera 0.
assert(0==NULL);  // in C++ sempre vero, in C può essere falso
void*p=NULL;
assert(p==0);  // in C++ sempre vero, in C può essere falso
void*p=NULL;
int i=(int)p;
assert(i==0);  // in C++ sempre vero, in C può essere falso
void*p=0;
assert(p==NULL);  // in C++ sempre vero, in C può essere falso
void*p;
memset(&v,0,sizeof(v));
int i=(int)p;
assert(p==NULL);  // può essere falso sia in C che in C++
assert(p==0);     // può essere falso sia in C che in C++
assert(i==0);     // può essere falso sia in C che in C++
Nota: Andrea mi confermi queste due delle quali non sono certo?
// la funzione chiama il SO e ritorna un puntatore ad una
// zona di memoria che a livello HW ha indirizzo 0x01234567
void*p=hw_address_from_os();
int i=(int)p;
assert(p==0x01234567);  // credo sia vero sia in C che in C++
assert(i==0x01234567);  // credo sia vero sia in C che in C++
Nota: Di questa invece sono sicuro
// la funzione chiama il SO e ritorna un puntatore ad una
// zona di memoria che a livello HW ha indirizzo 0x01234567
void*p=hw_address_from_os();
int i=reinterpret_cast<int>(p);
assert(i==0x01234567);  // può essere falso
// ovviamente questo solo nel caso sizeof(i)==sizeof(v)
memcpy(&i,&v,sizeof(v)); 
assert(i==0x01234567);  // può essere falso


 In C non e' ammesso. Non so se la cosa e' ammessa in C++.
in C free(0) e' una chiamata valida che non fa nulla.  lo stesso in
c++ per compatibilita' (anche se chi usa free in c++ e' un tonto)
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it
Alan Turing thought the whole life about the question of whether
machines can think; a question of which we now know that it is
about as relevant as the question of whether submarines can swim.
                -- Edsger W. Dijkstra

          }
questo e' invece falso.  in un contesto di pointer, "0" viene
interpretato come "il puntatore nullo di questa piattaforma".


 3.b) Caso realloc in C: non ne ho idea! Qualcuno pu? verificare?
puoi riallocare un puntatore che puntava a 0 byte, ma non viceversa
kronos@dreamland:/tmp# cat p.c
#include <stdlib.h>
#include <mcheck.h>
int main () {
        int *p;
        mtrace();
        p=malloc(0);
        realloc(p,1);
/*      realloc(p,0);
	Errore!!
	Segmentation fault quando chiamo free()
*/      free(p);
        free(0);
	free(NULL);
        muntrace();
        return 0;
}
kronos@dreamland:/tmp# gcc -Wall -op p.c
kronos@dreamland:/tmp# ./p
kronos@dreamland:/tmp# cat malloc.trace
= Start
@ [0x804849e] + 0x8049700 0
@ [0x80484b1] < 0x8049700
@ [0x80484b1] > 0x8049700 0x1
@ [0x80484bf] - 0x8049700
@ [0x80484c9] - (nil)
@ [0x80484d3] - (nil)
= End
ciao
Kronos
-- 
Home: 
http://kronoz.tsx.org
Ci sono due cose che l'uomo non puo' nascondere:
essere ubriaco ed essere innamorato.

Kronos, io parlavo dello standard, non di una
implementazione. Non e' molto utile sapere come si
comporta un dato compilatore (salvo forse per chi lo usa).
Ma in un forum come questo cio' che conta soprattutto e'
cosa dice lo standard. Se sul tuo compilatore qualche cosa
funziona non significa che lo standard esiga che funzioni,
puo' anche essere "undefined".
Viceversa se non funziona non significa che non debba 
funzionare, a meno che non hai la certezza assoluta che il
tuo compilatore e' 100% compliant. E io non ne sarei certo
neppure se lo avessi scritto io, il compilatore!


 puo' anche essere "undefined".
Lo so l'ho letto il manifesto!
ma si dice anche che il gcc sia uno dei compilatori piu` fedeli allo
standard, ed io ho usato solo funzioni della libreria standard
btw sono sicuro di tutte le affermazioni (nel manuale di dice
"conforming to the standard bla bla bla") tranne che su quella di
realloc (ma anche la funzione realloc viene dichiarata conforme allo
standard), che ho verificato sperimentalmente
ciao
Kronos
-- 
Home: 
http://kronoz.tsx.org
La vispa candela bruciava l'erbetta
creando un'essenza alquanto sospetta;
sembrava l'odore di una sacrestia
ma presto mi accorsi che era maria.

inspiegabilmente rispettato lo standard sotto questo aspetto.
Chiedo scusa, cmq ne sei sicuro? Nei corsi delle varie riviste come Dev o
IoProgrammo dicono tutte che viene restituito OxOO. Infatti in molti codici
ho letto:
    int* ptr = new int[5];
    if( prt == =Ox00) /* o == NULL */ {}
? 
Ciao.
-- 
La classifica dei prodotti MS:
C#, la migliore barzelletta di Bill Gates.
Visual C++, il meno standard dei compilatori C++.
J++, la copiatura più riuscita.
Windows, il più instabile.


    if( prt == =Ox00) /* o == NULL */ {}
prova a chiedere a quelle riviste, secondo loro, a cosa serve bad_alloc.


assert(i==0x01234567);  // puo' essere falso
Puo' essere falso sia in C che in C++.


del C/C++, o sbaglio?
Io ho sicuramente lavorato con compilatori che con free(NULL) si
incacchiavano come pochi... Forse non erano pero' standard su
questa cosa...


c++ per compatibilita' (anche se chi usa free in c++ e' un tonto)
Due cose:
 A) dove hai letto che free(0) e' ammesso ? E' qualcosa di
    presente nello standard C oppure nello standard C++ ?
    Io non sto dicendo che non e' vero ma che non ne sono
    sicuro e che sicuramente ho lavorato con piattaforme in
    cui fare free(0) corrispondeva a cercarsi grane (anche
    se come ho gia' detto forse su questo punto non erano
    compilant con quanto dice lo standard).
    Sia il g++ che VC++ documentano che e' ammesso free(0)
    ma questo e' un po' pochino per dire che e' standard...
    si tratta di compilatori che certo non si sono mai
    tirati indietro di fronte alla possibilita' di estendere
    quanto dice lo standard... la cosa giusta sarebbe
    controllare sullo documento di definizione dello standard.
 B) come implementeresti un allocatore globale custom (ad
    esempio per tenere sotto controllo la quantita' di
    memoria allocata in totale dal programma C++) senza
    utilizzare malloc e free ?


interpretato come "il puntatore nullo di questa piattaforma".
Appunto... lo 0 a destra del segno di "==" e' il puntatore nullo,
il valore di v e' invece stato modificato in modo che i suoi
bit sano tutti nulli. Le due cose non sono equivalenti: il fatto
che passi o meno dalla parte "non e' detto che passi di qui"
dipende dalla piattaforma (il programma potrebbe addirittura
crashare visto che v e' nel caso generale un puntatore non valido
e come tale non potrebbe in teoria essere neppure confrontato).


 ? 
E' supersicuro.


*/
realloc(p,0) e' equivalente a free(p). Se p non e' un
puntatore nullo allora non ti dovevi aspettare che
free(p) successivamente funzionasse: stai facendo due
volte la free dello stesso blocco.
Se p e' il puntatore nullo allora il probema e' simile
a quello di free(0).
Funziona sulla tua piattaforma ? De Sica direbbe
brobabilmente "embeh ? e un bel chissenefrega non ce
lo vogliamo mettere ?" :)
Il senso della domanda era originale era  "e'
previsto dallo standard C che free(0) funzioni ? e
dallo standard C++ ?"
HTH


? 
Si. Su questo sono sicuro. VC++ (6) torna NULL mentre lo standard
richiede che venga lanciata una exception.
Nella documentazione di VC++ e' descritto come fare in modo di
ottenere un comportamento aderente allo standard (e' per me
un mistero sul perche' MS si ostini a fare in modo che questo
non sia il comportamento di default).
Non si stratta comunque di una cosa grave dal punto di vista
pratico. Quando la memoria e' finita su Win vuol dire che il
tuo programma aveva gia' messo in ginocchio il sistema usando
tutta la memoria virtuale e il tu HD stava gia' frullando da
tempo come un pazzo -> ovvero -> l'utente aveva gia' fatto
ctrl-alt-del spazientito dall'attesa)
Il fatto che tu abbia letto codice simile su Dev o IoProgrammo
(senza che si dicesse che si tratta di una stortura introdotta
da VC++) non fa che confermare una cosa che ho scoperto molto tempo
fa sul mercato italiano per quello che riguarda i programmatori.
Purtroppo sulle riviste italiane scrivono "cani e porci"... a
volte gli articoli sono interessanti e scritti da gente competente
e a volte (anche se apparentemente interessanti) sono
semplicemente cumuli di sciocchezze ... e' questione di fortuna.
Quello che manca e' un serio controllo di qualita' sui contenuti:
ho raccontato alcune mie esperienze con le riviste nella mia
homepage (documenti -> "fumo e arrosto", si parla anche di DEV).
Forse in "fumo e arrosto" si vede che ero veramente incavolato
con il mondo... l'ho scritto "a caldo" e forse non avrei dovuto.
Ancora oggi penso pero' che l'ambiente che si presenta a chi
inizia sia forse piu' ostile di quando ho iniziato io (e' meglio
avere poche indicazioni molto affidabili o avere molte indicazioni
poco affidabili ?)


     se p sta puntando a qualcosa).
Il memory leak e' sempre 1. Nel caso che p stia puntando
a qualcosa realloc ne fara' la free. Il discorso e' che
pero' ho avuto un memory leak (l'indirizzo del nuovo blocco
si e' perso nel nulla) e inoltre i miei vecchi dati non
sono piu' accessibili (non posso piu' usare p per trovarli).


     utilizzare malloc e free ?
Colpito :-)
Beh, anche malloc/free sono costrutti relativamente ad alto livello
(mantengono una tabella interna etc.); sotto Unix si appoggiano su
procedure piu' a livello del ferro che si chiamano brk/sbrk, ed io
ricorrerei a quelle.  Mi riferivo alla richiesta "normale" di allocare
sullo heap.


 dallo standard C++ ?"
questo l'avevo capito, il codice era a supporto delle affermazioni, non
viceversa
btw...
free() accetta il puntatore nullo e non esegue alcuna operazione
malloc(0) deve funzionare e restituire un puntatore valido
realloc era quello che mi aveva creato alcune perplessita`...
se il puntatore passato e` nullo allora questa chiamata e` equivalente 
a malloc(size)
il tutto per il C
ciao
Kronos
-- 
Home: 
http://kronoz.tsx.org


sullo heap.
Per usi "normali" ovviamente non ha senso usare malloc: la
cosa giusta e' secondo me allocare raw memory (in quei rari
casi in cui serve) usando operator new.
Lo standard secondo me quasi "consiglia" di usare malloc
per implementare un allocatore globale custom quando afferma
che e' garantito che malloc non si appoggia a operator new
per ottenere la memoria richiesta (e' un po' come se dicesse:
"se volete usare malloc per implementare operator new non
dovete preoccuparvi di entrare in un loop senza fine... poi
fate un po' quello che vi pare").
HTH


 e free viene discussa in due righe.
Vero; quando e' uscito il primo standard ansi/iso (c89) il
comportamento di free e' mutato a questo riguardo.  Visto che
ho speso ben US$18 per avere ISO/IEC 9899:1999, posso anche
darti il riferimento definitivo:
----------------------------------------------------------------------
7.20.3.2 The 'free' function
Synopsis: #include <stdlib.h>
          void free(void *ptr);
Description: the 'free' function causes the space pointed to by 'ptr'
  to be deallocated, that is, made available for further allocation.
  If 'ptr' is a null pointer, no action occurs.  Otherwise, if the
  argument does not match a pointer earlier returned by the 'calloc',
  'malloc' or 'realloc' function, or if the space has been deallocated
  by a call to 'free' or 'realloc', the behavior is undefined.


 Quindi voi mi confermate che non è vero?
Infatti. Pensa a questa situazione:
int * p1 = new int(5);
int * p2 = p1;
delete p1;
Se delete impostasse il puntatore p1 a 0 p2 resterebbe comunque al
valore originale di p1, mentre il programmatore potrebbe essere indotto
a pensare di non doversi piu' preoccupare della gestione dei suoi
puntatori.
Ciao,
Nicola

 fate un po' quello che vi pare").
Devi tenere presente due cose: primo, lo standard e' scritto piu' per
gli implementatori di compliatori che per gli utenti del linguaggio:
quasi "consiglia" di implementare gli operatori new/delete standard in
termini di malloc/free; secondo, lo standard e' scritto a posteriori,
ovvero la domanda sottintesa non e' "come si deve comportare?" bensi'
"visto che in molte implementazioni si comporta cosi', come lo
descriviamo?".
Questo per dire che i paragrafi 20.4.6 3-4 sono secondo me scritti piu'
per chi ha gia' implementato new e delete in termini di malloc e free,
che non per chi deve scrivere allocatori custom.
Ciao,
Nicola

 nuova struttura. Almeno in C++, in C non sono sicuro.
In C++ una struttura senza membri dati o funzioni membro virtuali puo'
non incrementare la dimensione di una struttura che la eredita: in tutti
gli altri casi ha dimensione diversa da 0.
 
I confronti tra puntatori e interi mi paiono un campo minato: non mi
pronuncio.
Ciao,
Nicola

 standard, ed io ho usato solo funzioni della libreria standard
Meglio di alcuni, peggio di altri... Un buon elemento di paragone e':
http://www.comeaucomputing.com/tryitout/
Almeno per vedere se il codice compila.
Ciao,
Nicola