string_view 真的在促进释放后使用错误吗?
Is string_view really promoting use-after-free errors?
根据一篇文章 (here and there),这段代码是一个错误的 use-after free 示例:
#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
时会被释放!这违背了我的调试经验。但我要你 confirm/verify/check 这个。
根据我的经验,stack/scope 变量在作用域的出口被释放(调用析构函数是更正确的措辞)。这意味着在这种情况下,这将发生在 std::cout << sv;
之后
但是我从来没有使用过string_view
,所以我不知道这个对象的任何内部机制。
如果这确实是一种危险行为,你能解释一下吗?
否则,我很高兴看到确认范围变量析构函数仅在当前范围的退出时自然地被调用,或者当异常被抛出时,中断当前范围中的线程。
编辑:
经过前两个答案,真的是use-after-free usage。
补充问题:你认为我们可以在 string_view 的定义中添加一个带有 delete 关键字的移动构造函数来禁止它吗?
这段代码的问题...
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
A 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)。
表达式 s + “World\n”
产生一个临时对象。这个临时 std::string
的生命周期刚好足以初始化 sv
。 sv
指向的内存在初始化后立即释放(临时对象销毁时)。
根据一篇文章 (here and there),这段代码是一个错误的 use-after free 示例:
#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
时会被释放!这违背了我的调试经验。但我要你 confirm/verify/check 这个。
根据我的经验,stack/scope 变量在作用域的出口被释放(调用析构函数是更正确的措辞)。这意味着在这种情况下,这将发生在 std::cout << sv;
但是我从来没有使用过string_view
,所以我不知道这个对象的任何内部机制。
如果这确实是一种危险行为,你能解释一下吗? 否则,我很高兴看到确认范围变量析构函数仅在当前范围的退出时自然地被调用,或者当异常被抛出时,中断当前范围中的线程。
编辑: 经过前两个答案,真的是use-after-free usage。
补充问题:你认为我们可以在 string_view 的定义中添加一个带有 delete 关键字的移动构造函数来禁止它吗?
这段代码的问题...
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
A 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)。
表达式 s + “World\n”
产生一个临时对象。这个临时 std::string
的生命周期刚好足以初始化 sv
。 sv
指向的内存在初始化后立即释放(临时对象销毁时)。