我读到字符串文字具有静态存储持续时间,这是否意味着对它们的引用始终有效?例如,以下代码是否安全:
std::function<void()> foo(const std::string& name){
// capture name by reference
return [&](){
std::cout<<"The name is "<<name<<std::endl;
};
}
int main() {
std::function<void()> func;
{
func = foo("test");
func(); // func called in the same scope
}
func(); // func called in the outer scope
}
如果我们首先根据该字符串文字创建一个字符串,然后引用该字符串,结果会怎样?
std::function<void()> foo(const std::string& name){
// capture name by reference
return [&](){
std::cout<<"The name is "<<name<<std::endl;
};
}
int main() {
std::function<void()> func;
{
std::string test = "test";
func = foo(test);
func(); // func called in the same scope
}
func(); // func called in the outer scope
}
不,这不安全。
name
不是对字符串文字的引用。字符串文字不是std::string
对象,因此std::string
会构造一个临时的、未命名的对象,并且name
是对该对象的引用。然后,您的 lambda 会捕获对同一临时对象的引用。此类临时对象的生存期在创建它们的完整表达式结束时结束,因此该对象的生存期在
func = foo("test");
表达式之后结束。如果您在该点之后调用func
,那么您将在其生存期结束后访问临时对象,这会导致未定义的行为。第二个程序的行为也是未定义的。您的 lambda 持有对 的引用
test
,并且该对象的生存期在其封闭范围结束时结束。func
在该点之后调用意味着test
在其生存期结束后访问,从而导致未定义的行为。字符串文字不是
std::string
对象。它们是 的简单数组char
。也就是说, 的类型"test"
是char[5]
。该数组具有静态存储持续时间。如果您要捕获对该数组的引用,那么您将是安全的;即以下内容是明确定义的: