|
|
|
![]() |
|
Strumenti |
![]() |
#1 |
Member
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; } 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(); ![]() Ringrazio in anticipo chiunque si interessi.
__________________
|
![]() |
![]() |
![]() |
#2 |
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
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 |
![]() |
![]() |
![]() |
#3 | |
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
![]() 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 ![]()
__________________
|
|
![]() |
![]() |
![]() |
#4 | |
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
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 |
|
![]() |
![]() |
![]() |
#5 | |
Senior Member
Iscritto dal: Oct 2005
Messaggi: 3306
|
Quote:
Se la utilizzi così hai un memory leak: Codice:
Func(1,2,getImage("abc")); Codice:
const char * img = getImage("abc"); Func(1,2,img); Func2(3,4,img); Chissà perchè il C++ venga sempre utilizzato come C con le classi... |
|
![]() |
![]() |
![]() |
#6 | |
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
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 |
|
![]() |
![]() |
![]() |
#7 | ||
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
![]() 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:
__________________
|
||
![]() |
![]() |
![]() |
#8 |
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
È 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); 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 |
![]() |
![]() |
![]() |
#9 | |
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
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 ![]()
__________________
|
|
![]() |
![]() |
![]() |
#10 | |
Senior Member
Iscritto dal: May 2004
Città: Napoli
Messaggi: 773
|
Quote:
![]()
__________________
If builders built buildings the way programmers wrote programs, then the first woodpecker that came along would destroy civilization. --Gerald Weinberg |
|
![]() |
![]() |
![]() |
#11 | |
Member
Iscritto dal: Jun 2010
Città: Asti
Messaggi: 85
|
Quote:
![]() 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.
__________________
|
|
![]() |
![]() |
![]() |
#12 | |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
Quote:
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. |
|
![]() |
![]() |
![]() |
#13 | |
Senior Member
Iscritto dal: Jun 2002
Città: Dublin
Messaggi: 5989
|
Quote:
![]()
__________________
C'ho certi cazzi Mafa' che manco tu che sei pratica li hai visti mai! |
|
![]() |
![]() |
![]() |
#14 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
|
![]() |
![]() |
![]() |
#15 |
Senior Member
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! |
![]() |
![]() |
![]() |
#16 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
|
![]() |
![]() |
![]() |
#17 |
Senior Member
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! |
![]() |
![]() |
![]() |
#18 |
Senior Member
Iscritto dal: Apr 2000
Città: Vicino a Montecatini(Pistoia) Moto:Kawasaki Ninja ZX-9R Scudetti: 29
Messaggi: 53971
|
|
![]() |
![]() |
![]() |
#19 |
Senior Member
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! |
![]() |
![]() |
![]() |
#20 |
Senior Member
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.
|
![]() |
![]() |
![]() |
Strumenti | |
|
|
Tutti gli orari sono GMT +1. Ora sono le: 04:45.