为何用多C风格字符串初始化std::string会触发运行时错误?
用多C风格字符串初始化std::string的运行时错误解析
先看触发问题的代码:
std::string s{"abc", "bcd"}; std::cout << s << std::endl;
这段代码编译能通过,但运行时会抛出std::length_error并崩溃,错误信息如下:
terminate called after throwing an instance of 'std::length_error' what(): basic_string::_M_create [1] 89429 IOT instruction (core dumped) ./a.out
为什么编译能通过?
编译器会在std::string的构造函数中寻找最匹配的重载,核心逻辑如下:
- 排除
std::initializer_list<char>构造函数:这个构造函数要求列表元素是char类型,但"abc"这类字符串字面量会退化为const char*指针,指针转char属于窄化转换(指针通常占4/8字节,char仅1字节,转换会丢失大量信息),而列表初始化({})规则禁止窄化转换,因此该构造函数被排除。 - 匹配输入迭代器模板构造函数:
std::string有一个模板构造函数template<class InputIterator> string(InputIterator first, InputIterator last);,它接受两个输入迭代器,复制[first, last)范围内的字符。const char*完全满足输入迭代器的要求(支持解引用、递增操作),编译器会直接将两个字符串字面量的指针作为迭代器参数匹配该构造函数,无需转换,因此编译通过。
运行时错误的具体原因
字符串字面量"abc"和"bcd"是程序中独立的常量,它们在内存中的存储地址不确定:
- 如果
"bcd"的地址比"abc"高,构造函数会尝试复制两个地址之间的所有内存内容,这属于非法访问未授权内存,但不一定立刻崩溃; - 如果
"bcd"的地址比"abc"低,last("bcd"的指针)会小于first("abc"的指针)。由于计算长度的size_t是无符号整数,last - first会产生溢出,得到一个极大的数值。构造函数尝试分配对应大小的内存,远超系统可用上限,因此抛出std::length_error异常,最终导致程序崩溃。
内容的提问来源于stack exchange,提问作者Zlatan Radovanovic
相关产品推荐
相关产品推荐

