3

更新:getValue関数の場合、制御できないので、自分の側からできることはありますか?

stringとchar*basicについてちょっとばかげた質問があります。

char*値を返す関数を使用しています。

const char *getValue(const char *key)
{
    //if key found, and valueString is a string
      return valueString.c_str();
    //else
      return NULL;
}

次に、戻り値を保持するために文字列を初期化しました。

std::string value = getValue(key);

問題は、値が見つからない場合、つまり関数がNULLを返す場合は常に、割り当て行で例外が発生することです。しかし、法的な戻り値がある場合は、すべてが正常に機能しています。

私は疑問に思っています1.この使用法は完全に間違っていますか?char *とstringを決して混ぜてはいけないという意味ですか?2.そうでない場合、正当なポインタが返されると、文字列は自動的にコピーを作成して保存しますか?3.これを行うための最良の方法は何ですか?

ありがとう。

4

6 に答える 6

5

まず、valueStringがその関数に対してローカルである場合、返すポインターを使用すると、未定義の動作が発生します。

第二に、nullポインターを返すことが合理的であるかどうかは、そのポインターをどのように使用するかによって異なります。

絶対に、積極的にポインタをいじる必要がない限り、文字列を返すだけで、作業がずっと楽になります。

于 2012-04-11T18:40:22.853 に答える
4

NULL を返すことによってエラーの発生 (キーが見つからない場合) を報告することはお勧めできません。この場合、関数内で意味のある例外を生成する必要があります。のようなものNotFoundEx

その関数を制御できない場合は、安全なコードにラップする必要があります。

const char* getSafeValue(const char *key)
{
  const char* value = getValue(key);
  if(value == NULL)
    throw NotFoundEx();

  return value;
}


std::string value = getSafeValue(key);
于 2012-04-11T20:36:05.863 に答える
3

関数の動作を制御できないためgetValue()、に割り当てる前にNULLの戻り値を確認する必要がありますstd::string

std::string value;  // value is an empty string
const char *retVal = NULL;

if( ( retVal = getValue(key) ) != NULL ) {
  value.assign( retVal );
}
于 2012-04-11T18:49:23.757 に答える
0

std::stringとにかく値を操作しているので、 :のstd::string代わりにを返すだけです。char*

std::string getValue(const char *key) 
{ 
    if (key found)
        return valueString; 
    else 
        return std::string(); 
} 
于 2012-04-11T18:43:29.413 に答える
0

std::string範囲外の値を持つ が必要です。(char *)それを行うのに理想的な方法ではないかもしれませんが(より良い方法を参照)、範囲外の値をチェックすればboost::optional、機能します(スタックローカル変数を使用していないと仮定します) 。つまり、ここでの問題は実際には混合ではなく、「見つからない」ことをチェックしていないが、その場合に何か賢明なことが起こると盲目的に想定していることです。(char *)std::string

想定しないでください。キーが見つからない場合に何をする必要があるかを判断し、NULL(または他のものを使用することを選択した場合は他の帯域外)を確認します。

于 2012-04-11T18:43:42.407 に答える
0

最初の質問: データはどこから来たのですか? c_str()ローカル変数の結果を返すことはできません。これは未定義の動作であり、動作しているように見えるのは運が悪いだけです。valueStringより長期的なデータの単なるコピーである場合は、それをc_str 直接呼び出すことができます。ただし、より一般的には、返されるものは何でも、使用する前に有効であることを確認する必要があります。最も簡単な解決策 (ただし、常に可能であるとは限りません) は、 でセンティナル値を使用することですstring。たとえば、次のようになります。

std::string
getValue( std::string const& key )
{
    //  ...
    return condition ? valueString : std:;string();
}

たとえば、空の文字列をセンティナルとして使用します。

関数のセマンティクスが便利なセンティナル値を提供しない場合 (たとえば、関数が有効な値として空の文字列を返すことができる場合)、別のことを行う必要があります。

戻り値が長寿命のコンテナーでのルックアップの結果である場合、コンテナー内の要素へのポインターを返すことができる場合があります。ただし、一般に、ポインターは何を指すかという問題を引き起こします。寿命が十分にあるものがない場合は、ポインターを使用したくありません。

もう 1 つの可能性は、呼び出し元がデフォルト値を提供することです。

std::string
getValue( std::string const& key, std::string const& ifNotFound )
{
    // ...
    return condition ? valueString : ifNotFound;
}

これにより、番兵を定義する責任が呼び出し先に移ります。文字列のような場合、ほとんどの場合、呼び出し先が何もできない値が存在するため、センティナルとして使用できます。

最も一般的な代替手段は、ある種のFallibleまたはクラスです。ステータス (通常は のみ) と実際のデータ型のインスタンスMaybe を組み合わせたクラス オブジェクトです。boolデータが有効かどうかはステータスの値に依存するため、次のことを確認する必要があります。

Fallible<std::string>
getValue( std::string const& key )
{
    //  ...
    return condition
        ? Fallible<std::string>( valueString )
        : Fallible<std::string>();
}

これは多くの場合、内部的にもうまく機能します。

Fallible<std::string>
getValue( std::string const& key )
{
    Fallible<std::string> results;
    //  ...
    // At some point, I've got a valid return value, so I do:
        results.validate( valueString );
    // in a condition, of course...
    return results;
}

(頻繁で便利なパターンの例にすぎません。)

于 2012-04-11T18:59:29.903 に答える