考虑一个返回 a 的方法std::string_view
要么来自返回 a 的方法const std::string&
或来自空字符串。令我惊讶的是,以这种方式编写方法会导致悬空字符串视图:
const std::string& otherMethod();
std::string_view myMethod(bool bla) {
return bla ? otherMethod() : ""; // Dangling view!
}
https://godbolt.org/z/1Hu_p2 https://godbolt.org/z/1Hu_p2
看来编译器首先放置了一个临时的std::string
结果的副本otherMethod()
放在堆栈上,然后返回此临时副本的视图,而不仅仅是返回引用的视图。首先我想到了编译器错误,但 G++ 和 clang 都会这样做。
修复方法很简单:包裹otherMethod
转化为显式构造string_view
解决问题:
std::string_view myMethod(bool bla) {
return bla ? std::string_view(otherMethod()) : ""; // Works as intended!
}
https://godbolt.org/z/Q-sEkr https://godbolt.org/z/Q-sEkr
为什么会这样呢?为什么原始代码会在没有警告的情况下创建隐式副本?
因为这就是条件运算符的工作原理。
你正在调用?:
在两个操作数上,其中之一是类型的左值std::string const
另一个是类型的左值char const[1]
。条件运算符的语言规则......非常复杂。这相关规则 http://eel.is/c++draft/expr.cond#4 is:
否则,如果第二个和第三个操作数具有不同的类型并且其中一个具有(可能是 cv 限定的)类类型,或者如果两者都是相同值类别和相同类型的泛左值(除了cv- 限定,尝试形成从每个操作数到另一个操作数的类型的隐式转换序列。 [Note:对于该确定,将忽略诸如访问、操作数是否为位字段或是否删除转换函数之类的属性。 — 尾注 ]尝试从操作数表达式形成隐式转换序列E1
类型的T1
与该类型相关的目标类型T2
操作数表达式的E2
如下:
使用该过程,确定是否可以形成从第二操作数到为第三操作数确定的目标类型的隐式转换序列,反之亦然。如果两个序列都可以形成,或者可以形成一个序列但它是不明确的转换序列,则该程序是错误的。如果无法形成转换序列,则操作数保持不变,并按如下所述执行进一步检查。否则,如果可以形成恰好一个转换序列,则将该转换应用于所选操作数,并且对于本子条款的其余部分,使用转换后的操作数代替原始操作数。 [Note:即使可以形成隐式转换序列,转换也可能是格式错误的。 —end note ]
无法转换std::string const
到任一char const(&)[1]
or char const*
, 但是你可以转换 char const[1]
to std::string const
(内部嵌套项目符号)...这就是你得到的。类型的纯右值std::string const
。也就是说,您要么复制一个字符串,要么构造一个新字符串......无论哪种方式,您都会返回一个string_view
到立即超出范围的临时对象。
您想要的就是您拥有的:
std::string_view myMethod(bool bla) {
return bla ? std::string_view(otherMethod()) : "";
}
or:
std::string_view myMethod(bool bla) {
return bla ? otherMethod() : ""sv;
}
该条件运算符的结果是string_view
,这两种转换都是安全的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)