2016-10-21 5 views
1

文字列のための自分の関数をintに変換しようとしたところです。 My機能は次のとおりです。文字列を整数に変換する関数のエラーを処理する

int func(string s) 
{ 
    if error return -1; 
    else do something and return the value 
} 

私はちょうど1つの疑問を持って、私の文字列がs =は「-1」、そしてどのように私は「-1」エラーのためにとのために返さ区別う何だった場合文字列の右の変換。ご協力いただきありがとうございます。私の質問が十分にはっきりしていればと思う。

+8

できません。あなたの機能設計に欠陥があります。 – juanchopanza

+2

文字列が数字を表していない場合に例外をスローしないのはなぜですか? – Mureinik

+4

これは、エラー処理が常に難しい理由を示しています。一般的な場合、関数には、(1)成功/失敗の値と(2)戻り値の2つの出力があります。 2つのものを別々に返すことは迷惑であり、それは決して便利ではないので、2つのものを組み合わせようとするのは常に魅力的です。しかし、2つを組み合わせると(ここにしようとしている)、正常な戻り値のセットが成功/エラーの区別と異なる場合は、解決できないあいまいさに終わります。 –

答えて

1

あなたの機能設計は次のようになります。

int func(string s, int *out) 
{ 
    if error return -1; 
    else { 
     do something and set *out to the value; 
     return 1; 
    } 
} 

コメントが概説しているとして、それが有効な値とエラーの両方を表現する場合、戻り値は-1のために過負荷になっています。両方を表す整数値がないので、追加の戻り値が必要です。このデザインでは、関数の戻り値は成功または失敗を表し、*outパラメータは結果を返します。あなたはこれらの2つを交換することができます(パラメータは成功または失敗を受け取り、戻り値は値を受け取ります)。

+0

非常に一般的な規則は、成功の場合は「0」を返し、エラーの場合はゼロ以外を返します。これはブーリアンの共通のゼロ=偽、非ゼロ=真慣習の逆ですが、ゼロ以外のエラーコードでより多くの情報をエンコードすると便利です。 –

+0

@ Keith-Thompsonの代わりに、値を変換できない場合でも '0 'を返す' atoi'のような "サイレントエラー"があります。 –

+0

はい、これは代替案です - 悪いアイデア*とも呼ばれます。 –

3

いくつかのオプションがありますが、トレードオフは異なります。

1.例外。エラーの場合に例外をスローします。例外はコールサイトで直接捕捉する必要はありませんが、コール階層でさらに処理することができます。コール階層では、エラーを処理するコンテキストが増えます。 try-catchブロックで関数呼び出しを常にラップすると、例外の利点を誤解する可能性があります。

int func(const std::string& s); 

2.オプションの戻り値。std::optional、C++ 17(またはそれ以前はboost::optionalまたは技術仕様書(TS))として入手可能です。これは、値を返さないことが関数を呼び出すときに考慮しなければならない有効なケースであることを明示的に述べることです。

if (std::optional<int> i = func("hello")) // or even auto 
     use(*i); 

3.ポインタ戻り値:

std::optional<int> func(const std::string& s); 

クールなことは、このイディオムを可能にし、明示的なオペレータブール値です。前の点と同様のセマンティクスを使用すると、これは格納された要素が返されるときに必要になる可能性があります。検索で見つからない場合は、nullptrが返されます。 std::optionalとは対照的に、これにはメモリ/ライフタイム管理が必要であるという欠点があります(オブジェクトの呼び出しが長続きするか、動的に割り当てられるか)。本当に動的割り当てを使用する必要がある場合は、呼び出し側が明示的に削除する必要があるポインタを返しません。std::unique_ptr。ダイナミックアロケーションは高価であり、ほとんどの場合、intのような小さなオブジェクトの場合は過度に過剰です。また、const-correctnessについて考える必要があります。

int* func(const std::string& s); 
const int* func(const std::string& s); 
std::unique_ptr<int> func(std::string& s); 

4.チェックおよび出力パラメータイディオム。出力パラメータを取る関数を持つ。値を生成する場合は、そのパラメータに結果を書き込み、trueを返します。それ以外の場合はfalseを返します。

bool func(int& out); 

これにより、次のような呼び出しが可能です。欠点は、オブジェクトを直接初期化することができない(したがって、たとえば、const - 修飾された、デフォルトで構築されたオブジェクトまたは割り当て不可能なオブジェクトを使用できないことです)。

int value; 
if (func(value)) 
    use(value); 

5.アサーション。これは、多くの人々が見落としているもの、特にJavaのような言語から来ている人たちです。ここでは、ほとんどのエラーが例外的に扱われます。無効な値が返される唯一のケースは、関数の誤った呼び出し、つまりプログラム内の論理エラー(バグではありません)です。できるだけ早く認識可能にすることをお勧めします。デバッガは失敗したアサーションで直ちに停止しますが、生産的なコードは完全に最適化されています。

int func(const std::string& s); 

アサーションは、関数の事前条件または事後条件を確認するのに最適です。実行時に意味のある処理ができないエラーを通知する場合に特に便利です。彼らが失敗すると、あなたのプログラムロジックが壊れていることを意味します。そして、これが最初に起こってはいけないので、状況から回復する良い方法はありません。アプリケーションが予期しない状態にあるため、コードをさらに実行すると問題が悪化する可能性があります。

1

ただ例外をスローすることができます。

​​
0

私はboost::lexical_castを使用して、発信者がbad cast exceptionsを処理させるでしょう。

// will throw bad_lexical_cast if any issue. 
int convert(const std::string& num) { 
    return boost::lexical_cast<int>(num); 
} 


int main() 
{ 
    try { 
     std::cout << convert("1") << "\n"; 
     std::cout << convert("-1") << "\n"; 
     std::cout << convert("abc") << "\n"; 
    } catch (const boost::bad_lexical_cast& blc) { 
     std::cout << blc.what() << "\n"; 
    } 

return 0; 
} 

これは簡単で十分にテストされています。

簡単な方法では、boost::lexical_cast<T>()を使用して、convert関数を使用せずにラッパーのみを使用できます。

お試しくださいhere

+0

['std :: stoi'](http://en.cppreference.com/w/cpp/string/basic_string/stol)を使わないのはなぜですか? – juanchopanza

+0

@元コパパンザマゾヒズム。それは新しい黒です。 – user4581301

+0

@juanchopanza lexical_castはコンバージョンの種類によって柔軟性があるためです。 [lexical_castの詳細については、このリンクをチェックしてください](http://www.boost.org/doc/libs/1_55_0/doc/html/boost_lexical_cast/performance.html#boost_lexical_cast.performance.tests_description)。また、さまざまなタイプの統一されたインターフェイスを提供します。 – Dam

関連する問題