効率的な文字列連結
3つ以上の文字列を何気なく + 演算子で連結すると、必ずしも効率的には動作しないコードになります。
std::string a = "Hello"; const char b[] = "World"; char c = '!'; std::string x = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<message>" + a + ',' + b + c + "</message>";
実際は、std::basic_string の実装が賢ければ、(たぶん)文字数が少ない場合にヒープを使わないとか、メモリを多めに確保して再確保の回数を減らすとかしてくれるし、コンパイラもムーブとか戻り値最適化とかしてくれるので、そういうのにおまかせで良い場合は + 演算子を使いまくれば良いと思います。
そうでない場合のために concat() という関数を書きました。
std::string x = concat( "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "<message>", a, ',', b, c, "</message>");
引数に連結したい std::string や const char* や char を並べます。
実装は以下の通り。
#include <cstddef> #include <cstring> #include <string> namespace detail { struct ref { const char* ptr; std::size_t size; ref(const char* s) : ptr(s), size(std::strlen(s)) {} ref(const std::string& s) : ptr(s.c_str()), size(s.size()) {} ref(const char& c) : ptr(&c), size(1) {} }; } //namespace detail template <typename... Args> std::string concat(Args&& ...args) { detail::ref refs[] = { detail::ref(args)... }; std::size_t n = 0; for (detail::ref& r: refs) { n += r.size; } std::string s; s.reserve(n); for (detail::ref& r: refs) { s.append(r.ptr, r.size); } return s; }
最初は Variadic Template の練習用に書き始めたのですが、結局何の変哲もないコードになりました。