簡體   English   中英

std :: strings的std :: initializer_list的奇怪行為

[英]Strange behavior of std::initializer_list of std::strings

這個問題最有可能被問到,但我找不到答案。

下面的代碼用gcc編譯,但在運行時崩潰,使用std :: length_error( live )。

void test(const std::string &value) { std::cout << "string overload: " << value << std::endl; }

//void test(const std::vector<std::string> &) { std::cout << "vector overload" << std::endl; }

int main()
{
    test({"one", "two"});
}

從初始化字符串列表中創建字符串的能力似乎是有爭議的,例如,不能創建在上面的代碼中注釋掉的重載。

但即使允許這樣的結構,為什么會導致失敗呢?

它叫

string(const char* b, const char* e) 

string ctor重載。

僅當be指向相同的字符串文字時,它才有效。 否則它是未定義的行為。

對於初學者來說,沒有使用接受初始化列表的構造函數,因為這樣的構造函數看起來像

basic_string(initializer_list<charT>, const Allocator& = Allocator());
                              ^^^^^

因此,編譯器搜索另一個適當的構造函數,它會找到這樣的構造函數。 它是構造函數

template<class InputIterator>
basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());

這就是表達式"one""two"被認為是const char *類型的迭代器。

因此,函數test具有未定義的行為。

您可以編寫例如(假設具有相同內容的字符串文字在內存中存儲為一個字符串文字, 這不能保證並取決於所選的編譯器選項)。

#include <iostream>
#include <string>

void test(const std::string &value) { std::cout << "string overload: " << value << std::endl; }

//void test(const std::vector<std::string> &) { std::cout << "vector overload" << std::endl; }

int main()
{
    test({ "one", "one" + 3 });
}

你會得到一個有效的結果。

string overload: one

注意這個結構

{ "one", "two" }

不是std::initializer_list<T>類型的對象。 這種結構沒有類型。 它是一個braced braced-init-list ,用作初始化器。 只需編譯器首先嘗試使用具有std :: initializer_list類型的第一個參數的構造函數來與此初始化程序一起使用。

例如,如果您將使用類std::vector<const char *>那么編譯器將使用其構造函數與std :: initializer_list,並相應地使用此braced-init-list初始化其參數。 例如

#include <iostream>
#include <vector>

int main()
{
    std::vector<const char *> v( { "one", "two" } );

    for ( const auto &s : v ) std::cout << s << ' ';
    std::cout << '\n';
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM