0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

charに文字列を連結する際の注意

Posted at

#エラー再現
次のようなコードを記述した際に文章が途切れたエラーメッセージが出力されました。範囲外エラー的なエラーメッセージは出力されますが、その部分以外は正常に動いていました。
どうやら文字列にエラーメッセージが保管されている様子で、原因を探るために色々と実験してみました。
##コード

#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に文字列リテラルを繋げるのが良くないみたいだと分かります。

実験
Exp.cpp
#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::stringcharを含む文字列を代入、連結したいときは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
みたいな二回型変換が起こるのが良くないのかもしれません。

0
0
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?