Jump to content
Nokioteca Forum

Chiarmimento A Proposito Dei Tipi Di Funzioni E Cleanupstack


Andrea993
 Share

Recommended Posts

In Symbian C++ ci sono le funzioni L: che possono lasciare, le funzioni D che eliminano un oggetto, le funzioni C che inseriscono qualcosa nel CleanupStack.

Il problema è che se una funzione puà lasciare (L) non dovrebbe comunque inserire gli oggetti nel CleanupStack? Percui come differiscono dalle C.

Poi ho visto che alcune funzioni C dopo averle lanciate bisogna fare il pop di qualcosa nel CleanupStack, come faccio a sapere se e quanti pop devo fare?

Altra cosa nel CleanupStack devo inserire solo gli oggetti o anche variabili o altro?

Modificato da Andrea993
Link to comment
Condividi su altri siti

Il problema è che se una funzione puà lasciare (L) non dovrebbe comunque inserire gli oggetti nel CleanupStack?

Non e' detto che inseriscano nel CleanupStack...

Prendi la funzione TestL, ad esempio:

TBool TestL(RFs& fs, const TDesC& path)
{
 return BaflUtils::EnsurePathExistsL ( fs, path );
}

E' una funzione L eppure non ha la necessita' di inserire nulla nel CleanupStack, ne' di lasciare nulla nel CleanupStack...

Se, invece, RFs fosse locale alla funzione TestL(const TDesC& path) e non fosse preso come parametro, allora bisognerebbe inserire RFs nel CleanupStack, per poi distruggerlo prima dell'uscita dalla funzione, senza lasciare nulla nel CleanupStack.

Percui come differiscono dalle C.

C'e' differenza tra l'inserire nel cleanupstack ed a lasciarli nel cleanupstack.

Le C lasciano uno (o piu) oggetti nel cleanupstack (e quindi successivamente dova' seguire una PopAndDestroy()), le L non lasciano nulla nel cleanupstack...

Prendi ad esempio i due classici: NewL e NewLC.

La prima alloca l'oggetto ma non lo inserisce nel CleanupStack, la seconda fa la stessa cosa, ma lo inserisce nel CleanupStack.

La NewL la userai quando stai istanziando un oggetto che e' una proprieta' della classe (e sara' distrutto dal distruttore della classe)

La NewLC la usera quando stai instanziando un oggetto che usi dentro un determinato metodo e che hai intenzione di distruggere subito dopo il suo uso (tramite la PopAndDestroy)...

Poi ho visto che alcune funzioni C dopo averle loanciate bisogna fare il op a qualcosa nel CleanupStack, come faccio a sapere se e quanti pop devo fare?

Dipende dal caso specifico... come regola generale, il CleanupStack deve essere sempre bilanciato, ovvero nel tuo codice ci saranno sempre tante PushL quante Pop/PopAndDestroy.

Altra cosa nel CleanupStack devo inserire solo gli oggetti o anche variabili o altro?

Nel CleanupStack vai ad inserire qualsiasi cosa che necessiti di una allocazione di risorse.

- Oggetti R (es: RFs, RFile)

- qualsiasi cosa allochi con new

Fatta eccezione per le variabili di istanza (proprieta') perche' per la loro distruzione ci pensera' il distruttore.

Modificato da Il.Socio
Link to comment
Condividi su altri siti

Grazie mille ti sei spiegato perfettamente ora è molto più chiaro.

Invece (ELeave) lo devo usare ogni volta che alloco con new?

Ho trasformato questo codice "grezzo" che comunque funziona:

TBufC<31>* bufc;

for (TInt i=0;i<=nriga;i++)
{
bufc= new TBufC<31>(riga[i]);
console->Write(*bufc);
       delete bufc;
}		

In questo, che non funziona, in quanto non stampa.

TBufC<31>* bufc;

for (TInt i=0;i<=nriga;i++)
{
bufc= new (ELeave) TBufC<31>(riga[i]);
CleanupStack::PushL(bufc);
console->Write(*bufc);
CleanupStack::PopAndDestroy(bufc);
}					

Dove ho sbagliato e perchè?

Modificato da Andrea993
Link to comment
Condividi su altri siti

Argh... che schifezza :D

TBuf<31> non lo devi allocare con new (ELeave)

Lo usi e basta... e' sullo stack.

Se vuoi un descrittore che usa lo heap invece dello stack devi usare HBuf::NewLC() oppure RBuf.Create() oppure allochi grezzamente un area di TUint8 *

Il new (ELeave) alla fin, fine, non te lo ritrovi da nessuna parte dentro al codice perche' avrai tutti i tuoi bei metodi NewL() NewLC() che lo incapsulano a dovere.

Modificato da Il.Socio
Link to comment
Condividi su altri siti

Sì ma come avrei dovuto fare per convertire un TBuf16 in TBufC16 se non senza allocare un nuovo TBufC16 per ogni TBuf16?

Altrimenti avrei dovuto inserire una linea di questo tipo TBufC16 righeC[30]; , e la cosa sprecherebbe memoria inutilmente.

Al massimo ho provato così, però c'è comunque uno spreco di memoria dovuto all'allocamento di bufc e l'operazione bufc=riga; che è un lavoro non trascurabile.

TBufC<31> bufc;

for (TInt i=0;i<=nriga;i++)
	{
		bufc=riga[i];
		console->Write(bufc);			
	}

Modificato da Andrea993
Link to comment
Condividi su altri siti

Sì ma come avrei dovuto fare per convertire un TBuf16 in TBufC16 se non senza allocare un nuovo TBufC16 per ogni TBuf16?

Non e' necessario fare quella conversione...

Puoi semplicemente fare questo, o ti da forse qualche problema?

TBuf<31> buf16;       
for (TInt i=0;i<=nriga;i++)
{
       buf16.Copy(riga[i]);
       console->Write(buf16);
}   

Modificato da Il.Socio
Link to comment
Condividi su altri siti

Ma da dove nasce l'esigenza di convertire TBuf16 in TBufC16?

Se hai dichiarato una funzione in questa maniera:

TBool TestL(const TBufC& path)

allora, dovresti cambiare la dichiarazione cosi':

TBool TestL(const TDesC& path)

e gli passi direttamente TBuf16.

In qualsiasi caso, non esiste una conversione diretta che puoi fare tra TBuf16 e TBufC16, tramite qualche cast... dovrai necessariamente creare il nuovo buffer TBufC16:

TBuf<31> buf;

TBufC<31> bufc(buf);

Ma non mi viene in mente un solo caso reale in cui possa tornare utile questa conversione...

Piuttosto, puoi creare un

TPtrC ptr(buf);

cosi' non avviene nessuna copia dei dati ne' una nuova allocazione del buffer nello stack.

Modificato da Il.Socio
Link to comment
Condividi su altri siti

però c'è comunque uno spreco di memoria dovuto all'allocamento di bufc e l'operazione bufc=riga; che è un lavoro non trascurabile.

Non ti fare questi pippotti, e' tutto l'opposto...

Per buffer cosi' piccoli sono perfettamente trascurabili, anzi, completamente irrilevanti.

Meglio dare attenzione a 100.000 altre cose, molto piu' importanti e determinanti, prima di arrivare a scendere (eventualmente) in certe considerazioni.

Ma giusto per il piacere di disquisire, metti quel codice in una funzione, e l'utilizzo complessivo della memoria sara' perfettamente equivalente.

Nota che la copia avviene anche quando scrivi bufc= new TBufC<31>(riga);

Ed il codice che contiene le varie new/push/destroy sara' lievemente meno efficente a causa dell'overhead generato da queste operazioni aggiuntive.

Modificato da Il.Socio
Link to comment
Condividi su altri siti

Sì sì certo, anche il mio codice faceva una copia elemento per elemento ;)

Comunque l'esigenza deriva dal fatto che "Printf()" e "Write()" richiedono in input const TDesC &aDes. (Che poi l'uso di quel & nella definizione delle funzioni non mi è molto chiaro, è come se fosse puntatore ma ti basta passargli l'oggetto per valore e lui da solo si prende il puntatore anche se poi lo vedi come fosse un oggetto e non puntatore ad oggetto??)

Invece che tu sappia i progetti console come faccio a compilarli per symbian, mi basta avere l'exe, visto che voglio inserirlo manualmente in C:\sys\bin o magari flashando anche in (rofs2)\sis\bin.

Modificato da Andrea993
Link to comment
Condividi su altri siti

Comunque l'esigenza deriva dal fatto che "Printf()" e "Write()" richiedono in input const TDesC &aDes.

Sia TBuf, che TBufC sono entrambi dei TDesC (e piu' in generale tutti i descrittori sono TDesC) quindi puoi gia' passarli entrambi senza problemi e senza fare nessuna conversione.

Vedi qui:

idioms-descriptors.gif

(Che poi l'uso di quel & nella definizione delle funzioni non mi è molto chiaro, è come se fosse puntatore ma ti basta passargli l'oggetto per valore e lui da solo si prende il puntatore anche se poi lo vedi come fosse un oggetto e non puntatore ad oggetto??)

e' una reference ed indica "l'indirizzo di"... vedi qui...

TInt a = 10;

TInt *ptr = &a;

*ptr = 20;

// a vale 20

E' molto simile al passaggio tramite puntatore, ma consente di avere un implementazione della funzione piu' chiara, quindi, a meno che il valore NULL non sia un valore di input accettabile per la funzione, e' preferibile utilizzare la reference invece del puntatore (quando si sta realizzando una funzione e ci si trova a dover scegliere i parametri che prendera' in input la funzione)

Invece che tu sappia i progetti console come faccio a compilarli per symbian, mi basta avere l'exe, visto che voglio inserirlo manualmente in C:\sys\bin o magari flashando anche in (rofs2)\sis\bin.

I progetti console sono identici ai progetti con GUI... compili per "gcce urel" e distribuisci l'eseguibile esattamente come faresti per un progetto GUI.

Modificato da Il.Socio
Link to comment
Condividi su altri siti

Ah io credevo che TDes e TDesC fossero due classi a parte almeno da come lo spiega il workbook.

Sì, so cosa significa & in C\C++ ma non l'avevo mai visto usato nelle definizioni di funzione, comunque se passo ad una funzione "paperino" che richiede la & in input, l'oggetto "pippo":

...

{

...

classe1 pippo;

paperino(pippo)

...

}

paperino(classe1& pippo)

{

...

pippo.x=2;

...

}

dopo come mai se pippo è un puntatore ci posso accedere comunque con il ".", anzichè con "->"??

I progetti console sono identici ai progetti con GUI... compili per "gcce urel" e distribuisci l'eseguibile esattamente come faresti per un progetto GUI.

Si avevo provato però mi da' questo errore: \Nokia\devices\S60_3rd_FP2_SDK_v1.1\epoc32\release\ARMV5\urel\efsrv.lib: No such file or directory

Modificato da Andrea993
Link to comment
Condividi su altri siti

...

{

...

paperino(pluto)

...

}

paperino(mioTipo& pippo)

{

...

pippo.x=2;

...

}

dopo come mai se pippo è un puntatore ci posso accedere comunque con il ".", anzichè con "->"??

Ho cambiato i nomi che hai utilizzato per evitare ambiguita'...

Perche' pippo non e' un puntatore a mioTipo...

pippo e' un parametro che viene preso per riferimento (&) ed e' di tipo mioTipo.

Neppure pluto e' un puntatore a mioTipo... altrimenti se cosi' fosse:

mioTipo* pluto;

allora saresti costretto a passarlo come:

paperino(*pluto);

quindi non passi il puntatore, ma il suo valore.

Si avevo provato però mi da' questo errore: \Nokia\devices\S60_3rd_FP2_SDK_v1.1\epoc32\release\ARMV5\urel\efsrv.lib: No such file or directory

Accertati di compilare per gcce urel (non per armv5)

Link to comment
Condividi su altri siti

Grazie mille per tutto l'aiuto che mi stai dando.

Comunque io ho queste voci e seleziono l'ultima

immaginexh.jpg

EDIT: RISOLTO

Il problema derivava dal fatto che nel file mmp avevo inserito le librerie aggiuntive in "static libraries", andavano invece messe in "libraries".

EDIT 2:

Nonostante abbia compilato non riesco a lanciare l'eseguibile che mi ha creato da cellulare, l'ho semplicemente copiato in C:\sys\bin e ho tentato di lanciarlo

Modificato da Andrea993
Link to comment
Condividi su altri siti

Please sign in to comment

You will be able to leave a comment after signing in



Accedi Ora
 Share

×
×
  • Crea Nuovo...

Informazione Importante

Questo sito utilizza i cookie per analisi, contenuti personalizzati e pubblicità. Continuando la navigazione, accetti l'utilizzo dei cookie da parte nostra | Privacy Policy