Torna indietro   Hardware Upgrade Forum > Software > Programmazione

Recensione Borderlands 4, tra divertimento e problemi tecnici
Recensione Borderlands 4, tra divertimento e problemi tecnici
Gearbox Software rilancia la saga con Borderlands 4, ora disponibile su PS5, Xbox Series X|S e PC. Tra le novità spiccano nuove abilità di movimento, un pianeta inedito da esplorare e una campagna che lascia al giocatore piena libertà di approccio
TCL NXTPAPER 60 Ultra: lo smartphone che trasforma la lettura da digitale a naturale
TCL NXTPAPER 60 Ultra: lo smartphone che trasforma la lettura da digitale a naturale
NXTPAPER 60 Ultra è il primo smartphone con tecnologia NXTPAPER 4.0 per il display, un ampio IPS da 7,2 pollici. Con finitura anti-riflesso, processore MediaTek Dimensity 7400, fotocamera periscopica e modalità Max Ink per il detox digitale, NXTPAPER 60 Ultra punta a essere il riferimento tra gli smartphone pensati per il benessere degli occhi.
Un fulmine sulla scrivania, Corsair Sabre v2 Pro ridefinisce la velocità nel gaming
Un fulmine sulla scrivania, Corsair Sabre v2 Pro ridefinisce la velocità nel gaming
Questo mouse ultraleggero, con soli 36 grammi di peso, è stato concepito per offrire un'esperienza di gioco di alto livello ai professionisti degli FPS, grazie al polling rate a 8.000 Hz e a un sensore ottico da 33.000 DPI. La recensione esplora ogni dettaglio di questo dispositivo di gioco, dalla sua agilità estrema alle specifiche tecniche che lo pongono un passo avanti
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


Recensione Borderlands 4, tra divertimento e problemi tecnici Recensione Borderlands 4, tra divertimento e pro...
TCL NXTPAPER 60 Ultra: lo smartphone che trasforma la lettura da digitale a naturale TCL NXTPAPER 60 Ultra: lo smartphone che trasfor...
Un fulmine sulla scrivania, Corsair Sabre v2 Pro ridefinisce la velocità nel gaming Un fulmine sulla scrivania, Corsair Sabre v2 Pro...
Nokia Innovation Day 2025: l’Europa ha bisogno di campioni nelle telecomunicazioni Nokia Innovation Day 2025: l’Europa ha bisogno d...
Sottile, leggero e dall'autonomia WOW: OPPO Reno14 F conquista con stile e sostanza Sottile, leggero e dall'autonomia WOW: OPPO Reno...
Snapdragon X2 Elite Extreme, il cuore de...
Snapdragon 8 Elite Gen 5 è il nuovo rife...
Bombe Apple su Amazon: iPhone di scorsa ...
Micron: memoria HBM4 a 11 Gbps e patto d...
NVIDIA rende Audio2Face open source: ecc...
Logitech Signature Slim Solar K980+: 10 ...
Disney Plus aumenta i prezzi: si parte d...
Intel XeSS con Multi Frame Generation: u...
iPhone 16 a soli 700€ su Amazon: stile e...
Signature Slim Solar+ K980, la nuova tas...
Logitech MX Master 3S, il mouse perfetto...
Borderlands 4 per Switch 2 rinviato a te...
Reddit studia con Google una partnership...
La Ferrari elettrica che sembra una DeLo...
Xiaomi presenta una miriade di nuovi pro...
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: 04:45.


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