web-dev-qa-db-ja.com

C ++ 11初期化子リストが失敗します-ただし長さ2のリストのみ

長さ2の初期化子リストが特殊なケースのように見えるという事実まで、あいまいなロギングバグを追跡しました。これはどのように可能ですか?

コードは、CXXFLAGS=-std=c++11 -stdlib=libc++を使用して、Apple LLVMバージョン5.1(clang-503.0.40)でコンパイルされました。

#include <stdio.h>

#include <string>
#include <vector>

using namespace std;

typedef vector<string> Strings;

void print(string const& s) {
    printf(s.c_str());
    printf("\n");
}

void print(Strings const& ss, string const& name) {
    print("Test " + name);
    print("Number of strings: " + to_string(ss.size()));
    for (auto& s: ss) {
        auto t = "length = " + to_string(s.size()) + ": " + s;
        print(t);
    }
    print("\n");
}

void test() {
    Strings a{{"hello"}};                  print(a, "a");
    Strings b{{"hello", "there"}};         print(b, "b");
    Strings c{{"hello", "there", "kids"}}; print(c, "c");

    Strings A{"hello"};                    print(A, "A");
    Strings B{"hello", "there"};           print(B, "B");
    Strings C{"hello", "there", "kids"};   print(C, "C");
}

int main() {
    test();
}

出力:

Test a
Number of strings: 1
length = 5: hello

Test b
Number of strings: 1
length = 8: hello

Test c
Number of strings: 3
length = 5: hello
length = 5: there
length = 4: kids

Test A
Number of strings: 1
length = 5: hello

Test B
Number of strings: 2
length = 5: hello
length = 5: there

Test C
Number of strings: 3
length = 5: hello
length = 5: there
length = 4: kids

また、テストbの偽の文字列の長さは不確定であるように思われることも付け加えておきます。これは常に最初の初期化文字列よりも長くなりますが、最初の文字列の長さより1つ長いものから、2つの文字列の長さの合計まで変化します。イニシャライザで。

71
Tom Swirly

まず第一に、私が明白な何かを見逃していない限り、これは未定義の動作です。それでは説明させてください。ベクトルは、文字列の初期化リストから構築されています。ただし、このリストには1つの文字列しか含まれていません。この文字列は、内部の_{"Hello", "there"}_によって形成されます。どうやって?イテレータコンストラクタを使用します。基本的に、for (auto it = "Hello"; it != "there"; ++it)は_Hello\0_を含む文字列を形成しています。

簡単な例として、 ここを参照 。 UBは十分な理由ですが、2番目のリテラルがメモリ内の最初のリテラルの直後に配置されているように見えます。ボーナスとして、_"Hello", "Hello"_を実行すると、おそらく長さ0の文字列が得られます。ここで何も理解できない場合は、私は読むことをお勧めします フィリップの優れた答え

20
chris