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

Yur*_*riy 8 c++ constructor constructor-overloading initializer-list overload-resolution

这个问题很可能已经被问到了,但是我没有找到答案。

下面的代码使用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"});
}
Run Code Online (Sandbox Code Playgroud)

从字符串的初始化程序列表创建字符串的功能似乎有争议,例如,不能使上面的代码注释掉的重载成为可能。

但是,即使允许这种构造,为什么还会导致失败呢?

raf*_*x07 11

它呼吁

string(const char* b, const char* e) 
Run Code Online (Sandbox Code Playgroud)

字符串ctor重载。

仅当be指向相同的字符串文字时,它才有效。否则,它是不确定的行为。

  • @Yksisarvinen`template &lt;类InputIt&gt; basic_string(首先输入Input,最后输入Input,const Allocator&alloc = Allocator());` (3认同)

Vla*_*cow 6

对于初学者,没有使用过接受初始化列表的构造函数,因为这样的构造函数看起来像

basic_string(initializer_list<charT>, const Allocator& = Allocator());
                              ^^^^^
Run Code Online (Sandbox Code Playgroud)

因此,编译器搜索另一个合适的构造函数,并找到了这样的构造函数。它是构造函数

template<class InputIterator>
basic_string(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
Run Code Online (Sandbox Code Playgroud)

这就是表达式"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 });
}
Run Code Online (Sandbox Code Playgroud)

这样您将获得有效的结果。

string overload: one
Run Code Online (Sandbox Code Playgroud)

注意这个构造

{ "one", "two" }
Run Code Online (Sandbox Code Playgroud)

不是类型的对象std::initializer_list<T>。该构造没有类型。它是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';
}
Run Code Online (Sandbox Code Playgroud)

  • `{“ one”,“ one” + 3}`这不是基于两个`“ one”`都被编译为指向相同地址这一事实吗?这是按标准授予的吗? (4认同)
  • 是的,就像GCC中的--fno-merge-constants` (2认同)