条件运算符(?:)如何在C ++中工作?

时间:2017-12-19 03:52:19

标签: c++

我在下面写了代码片段:

#include <string>

int main() {
    std::string str = "test";
    (str == "tes") ? str.replace(0, 1, "T") : 0;
}

(See here)

不幸的是,它会导致logic_error

terminate called after throwing an instance of 'std::logic_error'
what():  basic_string::_S_construct NULL not valid

我想知道编译器构造字符串对象的原因吗?

2 个答案:

答案 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);
}

在上述情况下,您不会存储该值,但必须注意以下几个条件:

  1. 真实案例和虚假案件必须属于同一类型(或可转换为相同类型)。
  2. 即使该类型没有默认构造函数,它仍然有效(所以它比上面的更精细)。
  3. 这里的问题是您的代码期望类型为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;

可能会由一个体面的编译器优化,因为它没有任何明显的副作用 因此,您看到的异常可能会使用不同的优化级别来消除构建。