为什么std :: string_view在三元表达式中创建悬空视图?

gex*_*ide 19 c++ language-lawyer dangling-pointer string-view c++17

考虑std::string_view从返回a 的方法const std::string&或从空字符串返回的方法。令我惊讶的是,以这种方式编写方法会导致悬空的字符串视图:

const std::string& otherMethod();

std::string_view myMethod(bool bla) {
    return bla ? otherMethod() : ""; // Dangling view!
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/1Hu_p2

似乎编译器首先将std::string结果的临时副本otherMethod()放在堆栈上,然后返回此临时副本的视图,而不是仅返回引用的视图。首先,我想到了一个comipler错误,但是G ++和clang都这样做。

修复很容易:将其包装otherMethod为一个显式结构即可string_view解决此问题:

std::string_view myMethod(bool bla) {
    return bla ? std::string_view(otherMethod()) : ""; // Works as intended!
}
Run Code Online (Sandbox Code Playgroud)

https://godbolt.org/z/Q-sEkr

为什么会这样呢?为什么原始代码会在没有警告的情况下创建隐式副本?

Bar*_*rry 24

因为这就是条件运算符的工作方式。

您正在调用?:两个操作数,其中一个是type的左值,std::string const另一个是type的左值char const[1]。条件运算符的语言规则非常复杂。在相关的规则是:

否则,如果第二个操作数和第三个操作数具有不同的类型,并且具有(可能是cv限定的)类类型,或者除了cv -qualification以外,两者都是具有相同值类别和相同类型的glvalue,则尝试形成一个从每个操作数到另一个类型的隐式转换序列。[?注意:对于该确定,将忽略诸如访问,操作数是否为位字段或是否删除转换函数之类的属性。? -注完]尝试以从形成的操作数表达的隐式转换序列E1类型的T1相关的类型的目标类型T2的操作数的表达式E2如下:

  • 如果E2是一个左值,则目标类型为“的左值引用T2”,但要受约束,即在转换中引用必须直接绑定([dcl.init.ref])到glvalue。
  • 如果E2是一个xvalue,则[...]
  • 如果E2是prvalue 或以上任何一个转换序列都无法形成,并且至少一个操作数具有(可能是cv限定的)类类型:

    • 如果T1和T2是同一个类类型[...]
    • 否则,如果T2是的基类T1,则[...]
    • 否则,目标类型是E2在应用左值到右值,数组到指针和函数到指针标准转换后的类型。

使用此过程,确定是否可以从第二操作数到为第三操作数确定的目标类型形成隐式转换序列,反之亦然。如果可以形成两个序列,或者可以形成一个序列,但是这是模棱两可的转换序列,则程序格式不正确。如果无法形成转换序列,则操作数保持不变,并按如下所述进行进一步检查。否则,如果恰好可以形成一个转换序列,则将该转换应用于所选的操作数,并在此子节的其余部分中使用转换后的操作数代替原始操作数。[?注意:即使可能形成隐式转换序列,转换也可能格式错误。-?尾注?]

不能转换std::string const为char const(&)[1]或char const*,但是您可以转换 char const[1]为std::string const(内部嵌套的项目符号)...这样便可以得到。类型的prvalue std::string const。也就是说,您要么复制一个字符串,要么构造一个新的字符串……无论哪种方式,您都将a返回string_view到立即超出范围的临时目录。


您想要的就是拥有的东西:

std::string_view myMethod(bool bla) {
    return bla ? std::string_view(otherMethod()) : "";
}
Run Code Online (Sandbox Code Playgroud)

要么:

std::string_view myMethod(bool bla) {
    return bla ? otherMethod() : ""sv;
}
Run Code Online (Sandbox Code Playgroud)

该条件运算符的结果为,string_view两个转换都是安全的。

  • @Holt好吧,它是条件运算符,而不是三元运算符:-P (2认同)