我在下面写了代码片段:
#include <string>
int main() {
std::string str = "test";
(str == "tes") ? str.replace(0, 1, "T") : 0;
}
不幸的是,它会导致logic_error
:
terminate called after throwing an instance of 'std::logic_error'
what(): basic_string::_S_construct NULL not valid
我想知道编译器构造字符串对象的原因吗?
答案 0 :(得分:17)
三元运算符的实际效果如下:
std::string str = "test";
std::string _; // using _ since you don't store the variable
if (str == "tes") {
_ = str.replace(0, 1, "T");
} else {
_ = 0; // this calls std::string(nullptr);
}
在上述情况下,您不会存储该值,但必须注意以下几个条件:
这里的问题是您的代码期望类型为std::string
,基于true-case中的类型。 false-case中的类型是文字,可以认为是等同于NULL
的文字,因此可以被视为可转换为const char*
的{{1}}。如果您尝试从nullptr构造std::string
,则会抛出上述异常。
这实际上非常微妙,因为如果使用0以外的任何整数文字,编译器将抛出错误:
std::string
小心隐式转换。空检查和运行时错误非常优雅,可以避免以后出现细微错误或崩溃(几乎肯定是段错误)。
答案 1 :(得分:0)
所以,我想知道编译器构造字符串对象的原因吗?
因为std::string
提供了一个隐式构造函数,它使普通const char*
期望NUL
终止的c样式字符串。
有一个运行时断言,没有nullptr
(== 0
)与该构造函数一起传递,因此您看到了异常。
作为旁注:
您的陈述
(str == "tes") ? str.replace(0, 1, "T") : 0;
可能会由一个体面的编译器优化,因为它没有任何明显的副作用 因此,您看到的异常可能会使用不同的优化级别来消除构建。