[英]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重載。
僅當b
和e
指向相同的字符串文字時,它才有效。 否則它是未定義的行為。
對於初學者來說,沒有使用接受初始化列表的構造函數,因為這樣的構造函數看起來像
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.