#エラー再現
次のようなコードを記述した際に文章が途切れたエラーメッセージが出力されました。範囲外エラー的なエラーメッセージは出力されますが、その部分以外は正常に動いていました。
どうやら文字列にエラーメッセージが保管されている様子で、原因を探るために色々と実験してみました。
##コード
#include <iostream>
#include <string>
#include <array>
#include <vector>
int main()
{
std::array<std::string, 5> ary = {
"ary01", "ary02", "ary03", "ary04", "ary05"
};
std::vector<std::string> vec = {
"vec1", "vec2", "vec3"
};
std::string s_string_1 = vec.at(0).at(0) + ":" + ary.at(0);
std::string s_string_2 = ary.at(0).at(0) + ":" + vec.at(0);
std::cout << s_string_1 << std::endl;
std::cout << s_string_2 << std::endl;
return 0;
}
##出力
which is %zu)ary01
zu) >= this->size() (which is %zu)vec1
#何がダメだったのか
まず、std::string
型の変数を次のようにchar
型で初期化することはコンパイルエラーとなるのでできません
// error!
char x = 'a';
std::string s_string_1 = x;
std::string s_string_2 = 'a';
しかし、何か他の文字列と組み合わせてあげるとコンパイルエラーを吐かなくなります。
// error?
char x = 'a';
std::string s_string_1 = x + "bcd";
std::cout << s_string_1 << std::endl;
コンパイルエラーは吐きませんが出力では空の文字列が出力されます。
ここに
何か別のstd::string
型変数が間に入っているとコンパイルエラーも吐かず、出力も空文字列じゃなくなります。
char x = 'a';
std::string s_string_1 = "";
std::string s_string_2 = x + s_string_1 + "bcd";
std::string s_string_3 = 'a' + s_string_1 + "bcd";
std::cout << s_string_2 << std::endl;
std::cout << s_string_3 << std::endl;
abcd
abcd
多分char
に文字列リテラル繋げてるのが悪いんだなと思いつつ
ここから更に色々実験してみると確かにchar
に文字列リテラルを繋げるのが良くないみたいだと分かります。
実験
#include <iostream>
#include <string>
#include <array>
#include <vector>
int main()
{
std::array<std::string, 5> ary = {
"ary01", "ary02", "ary03", "ary04", "ary05"
};
std::vector<std::string> vec = {
"vec1", "vec2", "vec3"
};
char x = 'x';
std::string colon = ":";
std::string s1 = 'x' + ":";
std::string s2 = x + ":";
std::string s3 = 'x' + colon;
std::string s4 = x + colon;
std::cout << '[' << "s1: " + s1 << "] [" << "s2: " + s2 << "] [" << "s3: " + s3 << "] [" << "s4: " + s4 << ']' <<std::endl;
std::string test = "test";
std::string s5 = x + ":" + test;
std::string s6 = x + colon + test;
std::string s7 = x + ":" + ary.at(0);
std::string s8 = x + colon + ary.at(0);
std::cout << '[' << "s5: " + s5 << "] [" << "s6: " + s6 << "] [" << "s7: " + s7 << "] [" << "s8: " + s8 << ']' <<std::endl;
std::string s9 = ary.at(0).at(0) + ":" + test;
std::string s10 = ary.at(0).at(0) + colon + test;
std::string s11 = ary.at(0).at(0) + ":" + ary.at(0);
std::string s12 = ary.at(0).at(0) + colon + ary.at(0);
std::string s13 = vec.at(0).at(0) + ":" + vec.at(0);
std::string s14 = vec.at(0).at(0) + colon + vec.at(0);
std::cout << '[' << "s9: " + s9 << "] [" << "s10: " + s10 << "] [" << "s11: " + s11 << "] [" << "s12: " + s12 << ']' <<std::endl;
std::cout << '[' << "s13: " + s13 << "] [" << "s14: " + s14 << ']' << std::endl;
char y = 'a';
std::string s_string_1 = "";
std::string s_string_2 = y + s_string_1 + "bcd";
std::string s_string_3 = 'a' + "bcd" + s_string_2;
std::cout << s_string_2 << std::endl;
std::cout << s_string_3 << std::endl;
return 0;
}
[s1: is %zu) >= _Nm (which is %zu)] [s2: is %zu) >= _Nm (which is %zu)] [s3: x:] [s4:その結果
[s5: is %zu) >= _Nm (which is %zu)test] [s6: x:test] [s7: is %zu) >= _Nm (which is %zu)ary01] [s8: x:ary01]
[s9: test] [s10: a:test] [s11: ary01] [s12: a:ary01]
[s13: h is %zu) >= _Nm (which is %zu)vec1] [s14: v:vec1]
abcd
hich is %zu) >= this->size() (which is %zu)abcd
#あとがき
結論としては
std::string
にchar
を含む文字列を代入、連結したいときはchar
に隣接する文字列の型をstd::string
にしなくてはならないということでした。
(演算の順番を考えたときに一番初めにstd::string
とつながるようにすればよい?)
ちなみに
char
+ 文字列リテラル
はコンパイル通りましたけど
char
+ 文字列リテラル
+ 文字列リテラル
はコンパイル通りませんでした。
char
+ 文字列リテラル
でconst char*
となって文字列リテラル
がconst char[]
この二つが+
に対して無効なオペランドであるとのエラーが出ます。
const char*
とconst char[]
はstd::string
に型変換できるからそれを一緒に記述してやればコンパイルエラーが出なくなるのはわかるけど何故結果として空の文字列だとかエラーメッセージが格納されてるかは1ミリもわからないです。。。
char + const char[]
=> const char*
=> std::string
みたいな二回型変換が起こるのが良くないのかもしれません。