问题描述
考虑从返回const std::string&
的方法或从空字符串返回std::string_view
的方法.令我惊讶的是,以这种方式编写方法会导致字符串视图悬空:
Consider a method that returns a std::string_view
either from a method that returns a const std::string&
or from an empty string. To my surprise, writing the method this way results in a dangling string view:
const std::string& otherMethod();
std::string_view myMethod(bool bla) {
return bla ? otherMethod() : ""; // Dangling view!
}
似乎编译器首先将otherMethod()
结果的临时std::string
副本放在堆栈上,然后返回此临时副本的视图,而不仅仅是返回引用的视图.首先,我想到了一个comipler错误,但是G ++和clang都这样做.
It seems that the compiler first puts a temporary std::string
copy of the result of otherMethod()
on the stack and then returns a view of this temporary copy instead of just returning a view of the reference. First I thought about a comipler bug, but both G++ and clang do this.
修复很容易:将otherMethod
包装为string_view
的显式构造即可解决问题:
The fix is easy: Wrapping otherMethod
into an explicit construction of string_view
solves the issue:
std::string_view myMethod(bool bla) {
return bla ? std::string_view(otherMethod()) : ""; // Works as intended!
}
为什么会这样?为什么原始代码会在没有警告的情况下创建隐式副本?
Why is this the case? Why does the original code create an implicit copy without warning?
推荐答案
因为这就是条件运算符的工作方式.
Because that's how the conditional operator works.
您要在两个操作数上调用?:
,其中一个是类型为std::string const
的左值,另一个是类型为char const[1]
的左值.条件运算符的语言规则非常复杂. 相关规则为:
You're invoking ?:
on two operands, one of which is an lvalue of type std::string const
and the other is an lvalue of type char const[1]
. The language rule for the conditional operator is... really complicated. The relevant rule is:
- 如果E2是左值,则目标类型为对
T2
的左值引用",但要受约束,即转换中引用必须直接绑定([dcl.init.ref])到glvalue. li> - 如果E2是一个xvalue,则[...]
-
如果E2是prvalue ,或者以上转换序列都不能形成,并且至少一个操作数具有(可能是cv限定的)类类型:
- If E2 is an lvalue, the target type is "lvalue reference to
T2
", subject to the constraint that in the conversion the reference must bind directly ([dcl.init.ref]) to a glvalue. - If E2 is an xvalue, [...]
If E2 is a prvalue or if neither of the conversion sequences above can be formed and at least one of the operands has (possibly cv-qualified) class type:
- 如果
T1
和T2
是相同的类类型[...] - 否则,如果
T2
是T1
的基类,则[...] - 否则,目标类型是E2在应用从左值到右值,数组到指针和函数到指针的标准转换后的类型.
- if
T1
andT2
are the same class type [...] - otherwise, if
T2
is a base class ofT1
, [...] - otherwise, the target type is the type that E2 would have after applying the lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard conversions.
使用此过程,确定是否可以形成从第二操作数到为第三操作数确定的目标类型的隐式转换序列,反之亦然.如果可以形成两个序列,或者可以形成一个序列,但是这是模棱两可的转换序列,则程序格式不正确.如果无法形成转换序列,则操作数将保持不变,并按如下所述执行进一步检查.否则,如果恰好可以形成一个转换序列,则将该转换应用于所选的操作数,并且在本节的其余部分中,将使用转换后的操作数代替原始操作数. [注意:即使可以形成隐式转换序列,转换也可能格式错误. — 尾注]
Using this process, it is determined whether an implicit conversion sequence can be formed from the second operand to the target type determined for the third operand, and vice versa. If both sequences can be formed, or one can be formed but it is the ambiguous conversion sequence, the program is ill-formed. If no conversion sequence can be formed, the operands are left unchanged and further checking is performed as described below. Otherwise, if exactly one conversion sequence can be formed, that conversion is applied to the chosen operand and the converted operand is used in place of the original operand for the remainder of this subclause. [ Note: The conversion might be ill-formed even if an implicit conversion sequence could be formed. — end note ]
无法将std::string const
转换为char const(&)[1]
或char const*
,但是您可以将 char const[1]
转换为std::string const
(内部嵌套的项目符号)...你得到.类型为std::string const
的prvalue.也就是说,您要么复制一个字符串,要么构造一个新的字符串...无论哪种方式,您都将string_view
返回到立即超出范围的临时目录.
Can't convert std::string const
to either char const(&)[1]
or char const*
, but you can convert char const[1]
to std::string const
(the inner nested bullet)... so that's what you get. A prvalue of type std::string const
. Which is to say, you're either copying one string or constructing a new one... either way, you're returning a string_view
to a temporary which goes out of scope immediately.
您想要的就是拥有的东西
What you want is either what you had:
std::string_view myMethod(bool bla) {
return bla ? std::string_view(otherMethod()) : "";
}
或:
std::string_view myMethod(bool bla) {
return bla ? otherMethod() : ""sv;
}
该条件运算符的结果为string_view
,两次转换均是安全的.
The result of that conditional operator is a string_view
, with both conversions being safe.
这篇关于为什么std :: string_view在三元表达式中创建悬空视图?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!