2017-05-25 1 views
-2

私はBillというクラスを持っています。クラスのプロパティの中には、intcategoryと呼ばれるものがあります。 請求書を印刷するときには、番号ではなくカテゴリの名前が表示されます。だから私は、対応する文字列にcategory整数に変換するために、この静的なヘルパー関数を書きました:C++オーバーロード演算子<<静的ヘルパーメソッドを使用してアクセス違反エラーを作成する

// 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); 
    } 
} 

は今、私はこのようなBillクラス定義のoperator<<外をオーバーロードしようとした:

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

bill型のオブジェクトを作成し、このコード行を実行すると、エラーが発生します。 cout << billObject;

これで十分ではない情報があれば、私はもっと喜んで追加します。 このエラーを解決するにはどうすればよいですか?

+3

'のstd ::文字列&を回復する機会を与えるために、' - >は 'のstd :: STRING' – Geoff

+1

、このような問題を解決するための適切なツールですあなたのデバッガ。スタックオーバーフローを尋ねる前に、コードを一行ずつ進める必要があります。詳しいヘルプは、[小さなプログラムをデバッグする方法(Eric Lippert)](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/)を参照してください。少なくとも、問題を再現する[最小、完全、および検証可能](http://stackoverflow.com/help/mcve)の例と、デバッガでの観察結果を含めるように質問を編集する必要があります。 –

+0

@πάνταῥεscreensあなたがスクリーンショットを見ると、私は実際にプログラムをデバッグしています:) –

答えて

2

コンパイラは、getCategoryByNumber関数のコンテキストでC文字列からstd::stringオブジェクトを作成し、それへの参照を返し、関数が復帰すると即座に削除されます。

の代わりにconst char*またはstd::stringを返すことを検討してください。getCategoryByNumber

+2

この関数が終了すると、作成された一時文字列のデストラクタが呼び出されます。実行後、オブジェクトの存続期間が終了し、オブジェクトの存続期間が終了した後にオブジェクトを使用しようとするとUBになります。 – NathanOliver

+0

@ NathanOliverこれは、発言を除いて私の答えを繰り返します。この理由はここにあります。破壊されたオブジェクトの即時参照解除は、通常のランタイムよりも慎重なメモリレイアウトを使用するデバッガなどで誤って動作する可能性があります。一週間前のように私に起こった。あなたのアプリケーションが普通に動作しなくてもGDBの下で動作するのは本当に面倒ですね。 – iehrlich

+1

私はあなたの下降音が1行目と3行目から来ていると思うので、戻ってそれらを読むべきです:) – George

4

コンパイラは、 "ローカルオブジェクトへの参照の返却"または同様の警告を表示する必要があります(すべての警告をオンにした場合は、常にそうする必要があります)。あなたはまた、exit()を呼び出し避けなければならないが、その代わりにthrow例外は、アプリケーション・プログラムに

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。後で読む人のために、それを捕まえて処理することができるだけでなく、それが捕捉されなければ、人間にとって読みやすいエラーメッセージが表示されることがよくあります。 「なぜ%#@ * ^がプログラムをクラッシュさせたのですか? – user4581301

関連する問題