7

そのため、文字列を結合する場合、多くの場合、次のような一定のコンポーネントがあります。

std::string s;
s += initial_string;
s += "const string";
s += terminating_string;

これは単なるデモンストレーションです。文字列操作は、かなり複雑で詳細になる可能性があります。そのため、const 部分を実行すると、実装は長さを「認識しない」ことになり、効果的に実行さstrlen()れます。長さはコンパイル時にわかっているため、これは明らかに無駄です。const 文字列部分をこれに置き換えると、かなり高速になることをテストしました (何らかの理由で x64 ではかなり高速です)。

s.append("const string",12);

実際に文字を数えるのは煩わしく、時間がかかり、エラーが発生しやすいため、これは少し優れています。

s.append("const string",sizeof("const string")-1);

これはまだエラーが発生しやすい (つまり、最初の部分を変更するが、2 番目の部分を変更するのを忘れる) ため、マクロがこれを助けることができます。

#define strnsizeof(s) s,sizeof(s)-1
s.append(strnsizeof("const string"));

質問1:これに対するより良い/よりクリーンなソリューションを持っている人はいますか?

<<また、演算子を使用して文字列やその他のさまざまなオブジェクト型を連結する拡張文字列クラスもあります。同様の問題がここにありますが、これは(私にとって)素晴らしくてきれいです:

s << initial_string << "const string" << terminating_string;

自分のオブジェクト型 (長さはコンポーネント) の演算子がある場合、追加操作は高速で簡単ですが、const char *ここで再び取得すると、コンパイル時に一定であっても長さが得られません。const char *したがって、次の行に沿って a と長さを取る小さな構造を作成することで、それを高速化できます。

s << initial_string
    << MyStr::ConstBuf(strnsizeof("const string"))
    << terminating_string;

少年は醜くなっています。したがって、それもマクロ化できます。たとえば、次のようになります。

#define MyStrConst(s) MyStr::ConstBuf(s,sizeof(s)-1)
s << initial_string
    << MyStrConst("const string")
    << terminating_string;

より良いですが、素晴らしいとは言えません。

質問 2: 定数文字列をカプセル化するよりも優れた/よりクリーンなソリューションを得た人はいますか?

4

5 に答える 5

3

質問へのコメントは、次のようなテンプレートになりました。

template<size_t SZ> std::string& operator<<( std::string &s, const char(&arr)[SZ] ) {
    s.append( arr, SZ-1 );
    return s;
}

したがってs += "const string"、テンプレートの代わりに、次の場合に使用されます。

s << "const string"

さらに、以下がテンプレートを利用して一定のサイズも取得するように、拡張文字列クラスを更新することができました。

s << initial_string << "const string" << terminating_string;

編集:これは期待どおりに機能しません:

typedef struct { char buffer[32]; } ST;
ST st = { "1234" };
s << st.buffer;  // results in s with size 31!

これは、const 以外のテンプレートを使用して解決できます。たとえば、次のようになります。

template<size_t SZ> std::string& operator<<( std::string &s, char(&arr)[SZ] ) {
    s.append( arr ); // NOTE not using SZ here so a strlen happens
    return s;
}

だから今:

s << st.buffer;  // results in s with size 4

を除外する:

const ST cst = &st;
s << cst.buffer;  // results in s with size 31 again...

bufferご想像のとおり、が にある場合も同じ問題が発生classします。

于 2013-08-08T16:15:05.640 に答える
2

コンパイラの製造元に手紙を書いて、このケースに最適化しない理由を尋ねてください。それから、うまくいけば、定数文字列の連結が最適化のリストに追加され、誰もが何もしなくてもコードが速くなるでしょう!

それが私のお気に入りの解決策です。

于 2013-08-08T15:19:07.783 に答える
0

MSVC コンパイラにアクセスできません。十分な大きさのバッファーを予約すると、パフォーマンスが向上しますか?

これらの線に沿った何か

#include <iostream>
#include <string>

using namespace std;

string fast_concat(string s, const string& terminating_string) {

  static const string const_string("const string");

  s.reserve(s.size() + const_string.size() + terminating_string.size());

  s.append(const_string);

  s.append(terminating_string);

  return s;
}

int main() {

  cout << fast_concat("initial_string, ", ", terminating string") << endl;

}

(最初の引数を値でキャプチャするときと、結果を返すときの動きを期待しています。)

于 2013-08-08T16:07:43.107 に答える
0

strlenテンプレートを使用してコンパイル時に取得する方法は次のとおりです

#include <iostream>
#include <string>

using namespace std;

template <size_t N>
void concat_char_array(string& s, const char (&array)[N]) {

    s.append(array, N-1);
}

string fast_concat(string s, const string& terminating_string) {

  concat_char_array(s, "const string");

  s.append(terminating_string);

  return s;
}

int main() {

  cout << fast_concat("initial string, ", ", terminating string") << endl;

}

マクロと同じくらい高速である必要があります。

于 2013-08-08T16:22:22.037 に答える