1. ホーム
  2. スクリプト・コラム
  3. その他

[解決済み】 'std::logic_error' what(): basic_string::_M_construct null not valid エラーを修正する方法とは?

2022-01-12 05:33:44

質問

入力文字列がアルファベットか大文字かWi-Fiかどうかをチェックし、そうであればfalse/0を返し、そうでなければ実行を継続するという関数を実装する必要があります。

std::string myfunc(std::string input){
    std::string b="";

    if (!input.size()) return 0;
    for (int i = 0; i < input.size(); i++){

        if ( input[i] < 'a' || input[i] > 'z'|| isalpha(input[i]) || isupper(input[i]) ) return 0;
    }
    b = input;
    //just copy the input string for now.
    return b;
}

主なものは以下の通りです。

int main(){
    std::string input="Somthing";
    std::cout << myfunc(input)<< std::endl;
    return  0;
}

実行すると、エラーが発生します。

terminate called after throwing an instance of 'std::logic_error'
  what():  basic_string::_M_construct null not valid
Aborted (core dumped)

このプログラムは、この2つのエッジケースがなくてもうまく動きます。 

解決方法は?

問題は、2つの return 0; ステートメントを使用しています。この関数は std::string を受け入れるコンストラクタはありません。 int を入力とします。しかし、このコンストラクタは const char * のポインタがあり、0は暗黙のうちに変換される。しかし std::string をヌル char * ポインタは 未定義の動作 を投げることを選択し、実装は std::logic_error 例外が発生しますが、あなたのコードではキャッチしていません。

この場合、代わりに単純に空白の文字列を返します。

std::string myfunc(const std::string &input){
    if (input.empty()) return "";
    for (int i = 0; i < input.size(); ++i){
        char ch = input[i];
        if ( !((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) ) return "";
    }
    return input;
}

呼び出し側は、必要であれば、戻り値が空であるかどうかをチェックすることができます。

if (myfunc(input).empty())
    // error, do something
else
    // OK, do something else

を返す関数とどっちがいいんだろう? bool ではなく std::string :

bool isvalid(const std::string &input){
    if (input.empty()) return false;
    for (int i = 0; i < input.size(); ++i){
        char ch = input[i];
        if ( !((ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')) ) return false;
    }
    return true;
}

// if you still needed this function for something...
std::string myfunc(const std::string &input){
    if (!isvalid(input)) return "";
    return input;
}

if (!isvalid(input))
    // error, do something
else
    // OK, do something else