2017-05-25 2 views
-2

Ich habe eine Klasse mit dem Namen Bill. Unter den Eigenschaften der Klasse befindet sich eine mit der Bezeichnung category vom Typ int. Beim Drucken der Rechnung sollte anstelle der Nummer der Name der Kategorie angezeigt werden. Also schrieb ich diese statische Hilfsfunktion die category Ganzzahl in den entsprechenden Zeichenfolge zu konvertieren:C++ Überladen des Operators << Verwenden der statischen Hilfsmethoden Erstellen eines Zugriffsverletzungsfehlers

// Takes an integer representing the category and returns its corresponding name 
static const std::string& getCategoryByNumber(int category) 
{ 
    switch (category) 
    { 
    case 1: 
     return "Food"; 
    case 2: 
     return "Gift"; 
    case 3: 
     return "Fuel"; 
    case 4: 
     return "Electricity"; 
    case 5: 
     return "Clothes"; 
    case 6: 
     return "Holidays"; 
    case 7: 
     return "Water"; 
    case 8: 
     return "Fees"; 
    default: 
     exit(1); 
    } 
} 

Jetzt habe ich versucht, die operator<< außerhalb der Bill Klassendefinition so zu überlasten:

std::ostream& operator<<(std::ostream& os, Bill& bill) { 
    int category = bill.getCategory(); 
    const std::string& nameOfCategory = getCategoryByNumber(category); 
    std::cout << nameOfCategory.c_str(); 
    return os; 
} 

Shows debugging error

Der Fehler tritt beim Erstellen eines Objekts vom Typ Rechnung und Ausführen dieser Codezeile auf: cout << billObject;

Wenn dies nicht genug Informationen sind, werde ich gerne mehr hinzufügen. Wie kann ich diesen Fehler beheben und was verursacht es?

+3

'std :: string zu erholen &' -> 'std :: string' – Geoff

+1

Das richtige Werkzeug, solche Probleme zu lösen, ist dein Debugger. Sie sollten Schritt für Schritt durch Ihren Code * gehen, bevor Sie auf Stack Overflow nachfragen. Für weitere Hilfe lesen Sie bitte [Wie kleine Programme zu debuggen (von Eric Lippert)] (https://ericlippert.com/2014/03/05/how-to-debug-small-programs/). Zumindest sollten Sie Ihre Frage so bearbeiten, dass sie ein [minimales, vollständiges und verifizierbares] (http://stackoverflow.com/help/mcve) Beispiel enthält, das Ihr Problem zusammen mit den Beobachtungen, die Sie im Debugger gemacht haben, reproduziert . –

+0

@ πάνταῥεῖ Wenn Sie einen Blick auf den Screenshot werfen, bin ich tatsächlich Debuggen des Programms :) –

Antwort

2

Meine Vermutung, was wirklich hier passiert, ist der Compiler erstellt ein std::string Objekt aus einer C-Zeichenfolge im Kontext getCategoryByNumber Funktion, gibt einen Verweis darauf zurück, und das Objekt, das es verweist, wird sofort entfernt, sobald die Funktion zurückgibt.

Bitte berücksichtigen Sie die Rückgabe oder std::string statt std::string& von getCategoryByNumber.

+2

Für Sie beachten, wenn die Funktion endet der Destruktor für die temporäre Zeichenfolge, die erstellt wurde, aufgerufen wird. Nachdem die Lebensdauer des Objekts abgelaufen ist und versucht wird, ein Objekt nach Ablauf seiner Lebensdauer zu verwenden, wird UB verwendet. – NathanOliver

+0

@NathanOliver dies wiederholt meine Antwort mit Ausnahme der Bemerkung. Die Bemerkung ist aus einem bestimmten Grund da - eine sofortige Dereferenzierung von zerstörten Objekten könnte beispielsweise in Debuggern, die vorsichtigeres Speicherlayout als übliche Laufzeiten verwenden, versehentlich funktionieren. Ist mir vor einer Woche oder so passiert. Es ist wirklich fies, wenn Ihre Anwendung im normalen Lauf fehlschlägt, aber unter GDB funktioniert, oder? – iehrlich

+1

Ich schätze, deine Downvotes kommen aus der ersten und dritten Zeile, du solltest sie wieder lesen :) – George

4

Der Compiler sollte Sie gewarnt haben, "Verweis auf lokales Objekt zurückzugeben" oder ähnliches (wenn Sie alle Warnungen einschalten, was Sie immer tun sollten). Sie sollten auch vermeiden exit() Aufruf, sondern throw eine Ausnahme, das Anwendungsprogramm eine Chance zu geben

struct Bill 
{ 
    /* ... */ 
    int GetCategory() const; 
    static string GetCategoryName(int category) 
    { 
    switch (category) { 
    default: throw std::runtime_error("Bill: category '"+ 
             std::to_string(category)+"' unknown"); 
    case 1: return "Food"; 
    case 2: return "Gift"; 
    case 3: return "Fuel"; 
    case 4: return "Electricity"; 
    case 5: return "Clothes"; 
    case 6: return "Holidays"; 
    case 7: return "Water"; 
    case 8: return "Fees"; 
    } 
    } 
}; 

inline 
std::ostream& operator<<(std::ostream&os, Bill const&bill) 
{ 
    return os << Bill::GetCategoryName(bill.GetCategory()); 
} 
+0

Upvote für die Ausnahme. Für diejenigen von Ihnen, die später lesen, kann es nicht nur abgefangen und gehandhabt werden, aber wenn es nicht abgefangen wird, führt es oft zu einer verwendbaren, menschlich lesbaren Fehlermeldung, die für den Benutzer ausgedruckt wird. Viel weniger frustrierend als, "Warum die #% @ *^hat das Programm einfach abgestürzt?" – user4581301

Verwandte Themen