2

C スタイルの関数strftimeに便利なラッパーを書きたいと思います。そして、文字配列を文字列に、またはその逆に変換するいくつかのオプションにたどり着きました。これが私のコードです:

std::string Time::getAsFormattedString ( const std::string& format , const size_t& maxStringSize = 999 )
{

    char* timeArray = 0;
    std::string timeString;

    //  [OPTION_0]
    timeArray = reinterpret_cast <char*> (malloc(sizeof(char)*maxStringSize)));

    //  [OPTION_1]
    timeArray = const_cast <char*> (timeString.c_str());

    //  [OPTION_2]
    timeArray = &(*(timeString.begin()));

    strftime(timeArray,maxStringSize,format.c_str(),&this->time);
    timeString = timeArray;

    //  [OPTION_0]
    free(timeArray);

    return timeString;

}

メモリを解放する前に例外をスローできないため、№0オプションは安全に見えます(編集:例外をスローできます。timeString = timeArrayその行の周りにtry-catchが必要です)

№1 const-casting は常にハックのように見える

№2は、いくつかの問題があるかどうかわからないため、最高のようです

どれが最も安全で、正しく、最適で、おそらくベスト プラクティスであるかを教えてください。

ありがとうございました。

4

5 に答える 5

2

まず、クラッシュしない唯一のオプションは、ここではオプション 0 です。あなたが999バイトを割り当てたと言っているので、他のものはクラッシュしますが、実際には内部文字列にはおそらく1バイトしか割り当てられず、悲しいことが起こります.

ただし、ここでスタックに大量の文字を割り当てることで、おそらくこれを行うでしょう。

char timeArray[2048];
strftime(timeArray,2048,format.c_str(),&this->time);
return string(timeArray);

この方法では、キャストや動的割り当てを行う必要がなく、ほぼ確実に、よりきれいで高速になります。

于 2013-06-20T08:23:26.860 に答える
1

唯一可能な解決策は、オプション 0 です (ただし、いくつかの小さな調整を実行できます)。他の人が指摘しているように、標準では、c_str()メソッドによって返されるスペースは書き込み目的で使用されることを意図していないと述べています。実際にはstd::string、C 標準ライブラリ (C++標準ライブラリ)。

規格には次のように書かれています。

戻り値: 長さ size() + 1 の配列の最初の要素へのポインター。最初の size() 要素は *this によって制御される文字列の対応する要素と等しく、最後の要素は charT() によって指定された null 文字です。

Requires : プログラムは、配列に格納されている値を変更してはなりません。また、プログラムは、これと同じオブジェクトを指定するクラス basic_string の非 const メンバー関数への後続の呼び出しの後、戻り値を有効なポインター値として処理しません。

だから、私はあなたのコードを簡単に修正したいと思います:

const char * Time::getAsFormattedString(const std::string& format)
{
    static char timeArray[256];

    std::strftime( timeArray, 256, format.c_str(), &this->time );

    return timeArray;
}

これにより、メソッドのバッファがプログラムの起動時に作成され、継続的に再利用されるため、その側からメモリ エラーが発生することはありません (ヒープは変更されないため)。

唯一の問題は、関数の結果を格納する文字列を作成するためのスペースがスタックにあることですが、とにかくこれは関数を呼び出した後に発生し、関数自体はヒープに触れず、スタックの最小値。

const char *実際には、 からへの自動変換があるため、関数の有用性はそのままstd::stringです。通常の方法で安全に呼び出すことができます。

std::string strTime = time.getAsFormattedString( "%F %T" );

お役に立てれば。

于 2013-06-20T08:58:11.803 に答える
1

取得した文字列を変更することを意図していないため、オプション 1 と 2 は適切ではありませんstd::string::c_str()(c は を表しますconstant)。オプション 2 を使用するには、文字列の「サイズ変更」が必要です。しかし、文字列が同じバッファからコピーされることが保証されているかどうかはわかりません...

私の解決策は次のとおりです。

char timeArray[1000];     

(ただし、これは過剰です。同じ書式指定子を数回繰り返さない限り、100 文字を超える可能性は低く、非常に長くなります。そのため、「適切な」組み合わせで 1000 文字近くに到達することはありません。)

timeString = timeArrayの例外をスローする可能性があることに注意してください。そのためbad_alloc、その状況でメモリをリークしたくない場合は、スタックベースのストレージ (私の提案のように)、スマート ポインター、またはコードの一部を囲む try/catch ブロックを使用する必要があります。 .

于 2013-06-20T08:23:47.977 に答える
1

オプション 2 (またはさらに良いのは&timeString[0]) を優先する必要があります。

オプション 1 が悪いというのは正しいです。const_castオプション 0 では、少なくとも、のnew代わりにmalloc(そしてキャストを避けることで)コードを少しきれいにすることができます。

ただし、オプション 2 を優先します。

(ああ、コメンターが指摘したように、文字列自体に書き込んでいる場合は、明らかに、最初にサイズを変更して、範囲外に書き出さないようにする必要があります。反対票を考えると、おそらくそれについては明示的に)

于 2013-06-20T08:14:54.673 に答える