根据一篇文章(here和there),此代码是一个错误的使用后免费示例:
#include <iostream>
#include <string>
#include <string_view>
int main() {
std::string s = "Hellooooooooooooooo ";
std::string_view sv = s + "World\n";
std::cout << sv;
}
本文中指出,使用string
时将释放string_view
!这违背了我的调试经验。但我要您确认/验证/检查。
以我的经验,在作用域的出口处释放了堆栈/作用域变量(调用析构函数将是更正确的措辞)。这意味着在这种情况下,这种情况会在std::cout << sv;
但是我从未使用过string_view
,所以我对该对象的内部机制一无所知。
如果确实是危险行为,您能解释一下吗? 否则,我很高兴阅读确认消息,即范围变量析构函数仅在当前范围的出口自然地或在引发异常时中断当前范围中的线程才被调用。
编辑: 在前两个答案之后,这实际上是一种“先用后用”的用法。
子问题:您认为我们可以在string_view的定义中添加带有delete关键字的move构造函数以禁止这种情况吗?
答案 0 :(得分:3)
此代码存在问题...
std::string_view sv = s + "World\n";
...是sv
未被设置为s
,而是被表达式s + "world\n"
创建的无名 temporary 。整个表达式结束后(在分号处),临时立即被销毁。
是的,这是“免费使用后”类型的错误。
如果要延长该临时的寿命,则必须将其分配给将维持该临时变量的变量-例如新的std::string
对象:
std::string sv = s + "World\n"; // copy the temporary to new storage in sv
std::string_view
仅仅是字符串的“视图”,它本身并不是字符串。只要它“查找”的字符串有效,它才有效。
这里也有另一个怪癖。您还可以将 temporary 绑定到const
reference 上,从而延长了临时对象的寿命:
std::string const& sv = s + "World\n"; // just keep the temporary living
为什么允许从临时初始化std::string_view
?
我不能代表标准委员会发言,但我怀疑是std::string_view
被期望用作函数参数,以便可以将临时变量传递给函数(就像使用const ref一样)。显然,对于这种情况,生命周期很好。
如果我们禁止临时使用初始化,那么将否定std::string_view
的主要用途。在调用使过程笨拙的函数之前,您将被迫创建新的std::string
(或绑定到const ref)。
答案 1 :(得分:3)
表达式s + “World\n”
产生一个临时对象。此临时std::string
的生存期刚好足以初始化sv
。 sv
所引用的内存在初始化后立即被释放(当临时对象被销毁时)。