Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa
Marvel's Wolverine porta Logan in un'avventura inedita, violenta e fortemente narrativa, costruita attorno alla sua natura di combattente e al difficile rapporto con il proprio passato. Insomniac Games punta su combattimenti spettacolari, progressione e personalizzazione, inserendo l'azione in un mondo segnato dalla persecuzione dei mutanti. Un viaggio intenso, che alterna mattanza, esplorazione e momenti sorprendentemente emotivi.
DJI Romo 2: tante novità lo rendono un robot completo
DJI Romo 2: tante novità lo rendono un robot completo
Romo 2 è la seconda generazione di robot lavapavimenti di DJI, un modello che si caratterizza per la precisione nel sistema di navigazione e per il funzionamento particolarmente silenzioso. Con le modifiche introdotte in questa seconda versione, e un posizionamento di prezzo più allineato alla concorrenza, rappresenta una valida alternativa sul mercato delle soluzioni di pulizia domestica
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED
Il primo Sony con retroilluminazione True RGB alla prova del banco di misura e dei contenuti: luminanza enorme, colori accurati in HDR e un antiriflesso molto efficace. I limiti sono due sole HDMI 2.1 e il blooming fuori asse
Tutti gli articoli Tutte le news

Vai al Forum
Rispondi
 
Strumenti
Old 24-07-2010, 21:46   #1
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
[c++] problema con std::string che risulta illeggibile

Sera a tutti, ho un problema piuttosto strano in un metodo che ho scritto.
Il problema è che la stringa (restituita tramite il metodo c_str() come const char), risulta in un insieme di caratteri illeggibili.
Ma prima di andare avanti ecco la definizione del metodo:
Codice:
const char *Resources::getImage(const char *resourceID) {
	TiXmlNode *imagesNode = this->resourceFile.FirstChild("Images");
	TiXmlElement *resourceImage;

	for (resourceImage = imagesNode->FirstChildElement("Image");
		 resourceImage != NULL;
		 resourceImage = imagesNode->NextSiblingElement())
	{

		if (strcmp(resourceImage->Attribute("identifier"), resourceID) == 0) {
			if(resourceImage->Attribute("path")) {
                                // DA QUI LA STRINGA ILLEGGIBILE, resourcePath
				std::string resourcePath;
				resourcePath.append(this->resourcesRoot);
				resourcePath.append(std::string(resourceImage->Attribute("path")));

				return resourcePath.c_str();
			}
			else {
				std::string errorMessage("Missing reference for: ");
				errorMessage.append(resourceID);

				Engine::instance()->fatalError(errorMessage.c_str());
			}
		} 
		else {
			std::string alertMessage("Cannot get the resource reference to: ");
			alertMessage.append(resourceID);

			Engine::instance()->fatalError(alertMessage.c_str());
		}
	}
	return NULL;
}
Come si può intuire, questo metodo dovrebbe cercare in un file xml (gestito attraverso la libreria TinyXML.
Il problema è rappresentato da resourcePath che è una stringa assemblata con this->resourcesRoot che è una stringa contenente una porzione di path, e il contenuto dell'attributo "path" dell'elemento, che viene restituito sotto forma di const char *.

Se provo a stampare (per debug) da dentro la funzione, o a restituire il singolo this->resourcesRoot o resourceImage->Attribute("path") questi sono perfettamente leggibili e funzionanti, ma in questo punto:
Codice:
                                // DA QUI LA STRINGA ILLEGGIBILE, resourcePath
				std::string resourcePath;
				resourcePath.append(this->resourcesRoot);
				resourcePath.append(std::string(resourceImage->Attribute("path")));

				return resourcePath.c_str();
Si verifica il mistero, per completezza inserisco una immagine che mostra a schermo il risultato ottenuto (la scritta dopo è una informazione di debug, non ha alcuna attinenza con il metodo in questione):


Ringrazio in anticipo chiunque si interessi.
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 00:00   #2
Albi89
Senior Member
 
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
Quote:
Originariamente inviato da Opcode Guarda i messaggi
...
Il puntatore che ritorni col metodo c_str() è invalidato nel momento in cui la stringa viene deallocata (cioè all'atto del return).

Se non hai la possibilità di ritornare una std::string, puoi allocare dinamicamente una stringa C, copiarvi il contenuto della tua std::string usando strcpy e il metodo c_str() e dunque ritornare un puntatore a questa.
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
--Gerald Weinberg
Albi89 è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 10:50   #3
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da Albi89 Guarda i messaggi
Il puntatore che ritorni col metodo c_str() è invalidato nel momento in cui la stringa viene deallocata (cioè all'atto del return).

Se non hai la possibilità di ritornare una std::string, puoi allocare dinamicamente una stringa C, copiarvi il contenuto della tua std::string usando strcpy e il metodo c_str() e dunque ritornare un puntatore a questa.
Caspita che problema tedioso +
Purtroppo non ho possibilità di restituire direttamente una stringa in quanto il risultato è utilizzato come parametro per altre funzioni C, comunque la soluzione che mi hai proposto ha funzionato alla grande

Mi ero dimenticato dello scope della variabile, e sinceramente, pensavo che il risultato di c_str() fosse permanente, non dipendente dalla classe.

Grazie mille, mi hai risparmiato un'altra giornata di grattacapi
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 12:18   #4
Albi89
Senior Member
 
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Caspita che problema tedioso +
Purtroppo non ho possibilità di restituire direttamente una stringa in quanto il risultato è utilizzato come parametro per altre funzioni C, comunque la soluzione che mi hai proposto ha funzionato alla grande

Mi ero dimenticato dello scope della variabile, e sinceramente, pensavo che il risultato di c_str() fosse permanente, non dipendente dalla classe.

Grazie mille, mi hai risparmiato un'altra giornata di grattacapi
No, anzi, il puntatore restituito da c_str() è invalidato anche all'interno dello scope se la std::string viene modificata (almeno "da standard", se poi risulti ancora utilizzabile in alcuni casi non lo so, ma non bisogna farci affidamento).
Se è necessario riutilizzarne il contenuto, bisogna per forza copiarlo.
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
--Gerald Weinberg
Albi89 è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:05   #5
tomminno
Senior Member
 
Iscritto dal: Oct 2005
Messaggi: 3306
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Caspita che problema tedioso +
Purtroppo non ho possibilità di restituire direttamente una stringa in quanto il risultato è utilizzato come parametro per altre funzioni C, comunque la soluzione che mi hai proposto ha funzionato alla grande
Ricordati che poi devi deallocare l'array!
Se la utilizzi così hai un memory leak:
Codice:
Func(1,2,getImage("abc"));
sempre che Func non deallochi l'array, che è comunque molto pericoloso, perchè il giorno che devi chiamare:
Codice:
const char * img = getImage("abc");
Func(1,2,img);
Func2(3,4,img);
sei comunque fregato.

Chissà perchè il C++ venga sempre utilizzato come C con le classi...
tomminno è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:13   #6
Albi89
Senior Member
 
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Ricordati che poi devi deallocare l'array!
Se la utilizzi così hai un memory leak:
Codice:
Func(1,2,getImage("abc"));
sempre che Func non deallochi l'array, che è comunque molto pericoloso, perchè il giorno che devi chiamare:
Codice:
const char * img = getImage("abc");
Func(1,2,img);
Func2(3,4,img);
sei comunque fregato.

Chissà perchè il C++ venga sempre utilizzato come C con le classi...
Beh, tante volte la colpa non è dell'utente ma del dover far convivere più librerie, di cui magari alcune disponibili solo in C.

Ovviamente la necessità di deallocare esternamente c'è, non ne ho parlato perché incoraggio fortemente altre soluzioni (basti pensare che avere una allocazione nel tuo metodo, e una deallocazione a cura dell'utente del metodo, è rischiosissimo in ottica "black box" e renderebbe il tutto decisamente poco usabile da un ipotetico user della tua classe, senza considerare quanto si presti a tue distrazioni e leaks casalinghi).

Ti incoraggio fortemente a ritornare una std::string, e dunque a realizzare un wrapper per il tuo metodo che accetta solo char* (o, semplicemente, a passargliela tramite c_str(): in questo caso, e ammesso che tale metodo non debba modificare la stringa, sei sicuro della validità del puntatore per tutta la durata del metodo!).

Un'altra alternativa può essere ritornare una classe gestore della risorsa che incapsuli un char* e si occupi, oltre che di metterlo a disposizione del metodo chiamante, anche della sua deallocazione all'uscita dallo scope: sinceramente il gioco non vale la candela
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
--Gerald Weinberg
Albi89 è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:13   #7
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da Albi89 Guarda i messaggi
No, anzi, il puntatore restituito da c_str() è invalidato anche all'interno dello scope se la std::string viene modificata (almeno "da standard", se poi risulti ancora utilizzabile in alcuni casi non lo so, ma non bisogna farci affidamento).
Se è necessario riutilizzarne il contenuto, bisogna per forza copiarlo.
Capito, beh ti ringrazio della precisazione, mi sarà sicuramente utile per il futuro
Quote:
Originariamente inviato da tomminno Guarda i messaggi
Ricordati che poi devi deallocare l'array!
Ci avevo pensato, ma non ho trovato alcuna soluzione fruibile, poichè l'output viene dato in pasto alle funzioni di una libreria esterna, la maggior parte delle volte, infatti ci stavo proprio pensando, comunque stò implementando un sistema per vedere se la risorsa da caricare è già stata richiesta, e nel caso non fare nuovamente la trafila ma restituire direttamente path (una sorta di hash table per tenere traccia del risultato, in questo modo non ci sono dispersioni di memoria).
Quote:
Se la utilizzi così hai un memory leak:
Codice:
Func(1,2,getImage("abc"));
sempre che Func non deallochi l'array, che è comunque molto pericoloso, perchè il giorno che devi chiamare:
Codice:
const char * img = getImage("abc");
Func(1,2,img);
Func2(3,4,img);
sei comunque fregato.

Chissà perchè il C++ venga sempre utilizzato come C con le classi...
Hai qualche soluzione da consigliare?
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:18   #8
Albi89
Senior Member
 
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Hai qualche soluzione da consigliare?
È importante capire se la libreria esterna deve o meno modificare la stringa che riceve... se nel prototipo vedi che è qualcosa del tipo:
Codice:
funzioneEsterna(const char* s);
il tuo metodo potrebbe tranquillamente ritornare una std::string, e passarla come:
Codice:
funzioneEsterna(mioMetodo().to_str());
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
--Gerald Weinberg
Albi89 è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:25   #9
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da Albi89 Guarda i messaggi
È importante capire se la libreria esterna deve o meno modificare la stringa che riceve... se nel prototipo vedi che è qualcosa del tipo:
Codice:
funzioneEsterna(const char* s);
il tuo metodo potrebbe tranquillamente ritornare una std::string, e passarla come:
Codice:
funzioneEsterna(mioMetodo().to_str());
Caspita, quello che mi fai notare non è affatto sbagliato.
Almeno per le funzioni che accettano il risultato di getImage, i prototipi sono tutti o quasi const char *filename, visto che devono solo occuparsi di caricare le risorse, non di modificare il nome.

Mi sà che agirò in questo modo.
Grazie ancora una volta
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 15:27   #10
Albi89
Senior Member
 
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Caspita, quello che mi fai notare non è affatto sbagliato.
Almeno per le funzioni che accettano il risultato di getImage, i prototipi sono tutti o quasi const char *filename, visto che devono solo occuparsi di caricare le risorse, non di modificare il nome.

Mi sà che agirò in questo modo.
Grazie ancora una volta
Un'alternativa è mantenere il puntatore con uno scoped_array, ma mi sembra che l'altra soluzione sia più comoda
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization.
--Gerald Weinberg
Albi89 è offline   Rispondi citando il messaggio o parte di esso
Old 25-07-2010, 19:50   #11
Opcode
Member
 
L'Avatar di Opcode
 
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
Quote:
Originariamente inviato da Albi89 Guarda i messaggi
Un'alternativa è mantenere il puntatore con uno scoped_array, ma mi sembra che l'altra soluzione sia più comoda
Ehm si decisamente più comoda la precendente
E poi adottare questa soluzione vorrebbe dire aggiungere un'altra libreria, ed essendo la precedente una soluzione funzionante, mi stà bene anche evitare di aggiungere altro

Comunque hai fatto benissimo a linkare la risorsa, molto utile
Ciao.
Opcode è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 09:50   #12
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da Opcode Guarda i messaggi
Caspita che problema tedioso +
Purtroppo non ho possibilità di restituire direttamente una stringa in quanto il risultato è utilizzato come parametro per altre funzioni C, comunque la soluzione che mi hai proposto ha funzionato alla grande
Sinceramente non mi piace molto allocare una risorsa dentro ad una funzione e poi dover imporre al chiamante la deallocazione.
Le soluzioni che ti posso proporre sono queste:

Codice:
std::string myFunction(...)
{
   std::string s;
   ...
   return s;
}
otherFunction(myFunction(...).c_str(), ...);
Codice:
char * myFunction(char * buffer, ...)
{
   std::string s;
   ...
   strncpy(buffer, s.c_str(), MAX_PATH);
   return buffer;
}

char buffer[MAX_PATH + 1];
otherFunction(myFunction(buffer, ...), ...);

Ultima modifica di cionci : 27-07-2010 alle 10:15.
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:13   #13
DanieleC88
Senior Member
 
L'Avatar di DanieleC88
 
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
Quote:
Originariamente inviato da cionci Guarda i messaggi
Codice:
std::string myFunction(char * buffer, ...)
{
   std::string s;
   ...
   strncpy(buffer, s.c_str(), MAX_PATH);
   return buffer;
}
__________________

C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai!
DanieleC88 è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:15   #14
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da DanieleC88 Guarda i messaggi
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:22   #15
DanieleC88
Senior Member
 
L'Avatar di DanieleC88
 
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
Toh, funziona!
Crea l'oggetto std::string corrispondente a partire dal contenuto di buffer? Perché se è così a quel punto conviene usare direttamente std::string, no?

ciao
__________________

C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai!
DanieleC88 è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:30   #16
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da DanieleC88 Guarda i messaggi
Toh, funziona!
Crea l'oggetto std::string corrispondente a partire dal contenuto di buffer? Perché se è così a quel punto conviene usare direttamente std::string, no?

ciao
Era un errore, non avevo messo il valore di ritorno corretto
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:33   #17
DanieleC88
Senior Member
 
L'Avatar di DanieleC88
 
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
E infatti così mi pareva, ma mi compila e funziona pure!
(Almeno, con clang, ora provo gcc...)
__________________

C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai!
DanieleC88 è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:36   #18
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
Quote:
Originariamente inviato da DanieleC88 Guarda i messaggi
E infatti così mi pareva, ma mi compila e funziona pure!
Che funzionasse era ovvio, visto che std::string ha i costruttori adatti per fare quella conversione
cionci è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:40   #19
DanieleC88
Senior Member
 
L'Avatar di DanieleC88
 
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
Be' quello sì, ma non ero certo che il compilatore facesse implicitamente la costruzione dell'oggetto senza lamentarsi.
Beata ignoranza.
__________________

C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai!
DanieleC88 è offline   Rispondi citando il messaggio o parte di esso
Old 27-07-2010, 10:56   #20
cionci
Senior Member
 
L'Avatar di cionci
 
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
In teoria, con il passaggio del buffer, la cosa più "pulita" sarebbe passare anche la dimensione del buffer stesso.
cionci è offline   Rispondi citando il messaggio o parte di esso
 Rispondi


Marvel's Wolverine, la recensione: Logan torna protagonista in un'avventura brutale e intensa Marvel's Wolverine, la recensione: Logan torna p...
DJI Romo 2: tante novità lo rendono un robot completo DJI Romo 2: tante novità lo rendono un ro...
Sony Bravia 9 II: il True RGB alla prova, dove l'LCD sfida l'OLED Sony Bravia 9 II: il True RGB alla prova, dove l...
Geely EX5, un mese al volante: il SUV elettrico cinese che ci ha sorpreso (quasi) senza riserve Geely EX5, un mese al volante: il SUV elettrico ...
Mova Z70 Ultra Roller Complete: motore potente, rullo di lavaggio e l'IA a guidare Mova Z70 Ultra Roller Complete: motore potente, ...
Giochi Ubisoft su Steam senza Ubisoft Co...
Miami Beach ha autorizzato la maxi opera...
Apple regala un altro anno di funzioni s...
Alla fine è successo davvero: Vol...
Il meglio di Amazon del weekend in uno s...
Speciale TV in offerta su Amazon: Hisens...
Non c'è pace per Trezor: 347.000 e-mail ...
È un portatile Dell e li vale tut...
Apple iPhone 17 Pro Max 256GB a 1.195€ (...
GPT-6 Astra è davvero AGI o non s...
LG OLED G6S 48'' a 845€ e G6 55'' a 1368...
Mantax Otax: il malware Android che crip...
Musk incassa un altro maxi contratto IA:...
Le vendite di EV sono esplose in tutto i...
Avio si prepara ai test del Dimostratore...
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: 12:14.


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