临时参数值什么时候超出范围?

时间:2012-09-07 17:53:12

标签: c++

  

可能重复:
  Lifetime of temporaries

int LegacyFunction(const char *s) {
    // do something with s, like print it to standard output
    // this function does NOT retain any pointer to s after it returns.
    return strlen(s);
}

std::string ModernFunction() {
    // do something that returns a string
    return "Hello";
}

LegacyFunction(ModernFunction().c_str());

上面的例子很容易被重写,以使用智能指针而不是字符串;我多次遇到过这两种情况。无论如何,上面的例子将在ModernFunction中构造一个STL字符串,返回它,然后获取一个指向字符串对象内部的C风格字符串的指针,然后将该指针传递给遗留函数。

  1. 在返回ModernFunction之后,存在一个临时字符串对象。什么时候超出范围?
  2. 编译器是否可以调用c_str(),破坏此临时字符串对象,然后将悬空指针传递给LegacyFunction? (请记住,字符串对象正在管理c_str()返回值指向...)
  3. 的内存
  4. 如果上面的代码不安全,为什么它不安全,并且有一个更好,同样简洁的方法来编写它而不是在进行函数调用时添加一个临时变量?如果它安全,为什么?

2 个答案:

答案 0 :(得分:15)

LegacyFunction(ModernFunction().c_str());

在评估full expression之后(即从LegacyFunction返回后),销毁副本。

n3337 12.2 / 3

临时对象作为最后一步被销毁 在评估全表达式(1.9)时(词法上)包含创建它们的点。

n3337 1.9 / 10

完整表达式是不是另一个表达式的子表达式的表达式。如果是语言结构 被定义为产生函数的隐式调用,语言构造的使用被认为是一种 表达用于此定义的目的。对生命周期结束时生成的析构函数的调用 临时对象以外的对象是隐式完整表达式。转换应用于结果 表达式,以满足表达式出现的语言结构的要求 也被认为是完整表达的一部分。 [例如:

struct S {
S(int i): I(i) { }
int& v() { return I; }
private:
int I;
};
S s1(1); // full-expression is call of S::S(int)
S s2 = 2; // full-expression is call of S::S(int)
void f() {
if (S(3).v()) // full-expression includes lvalue-to-rvalue and
// int to bool conversions, performed before
// temporary is deleted at end of full-expression
{ }
}

答案 1 :(得分:9)

  

在返回ModernFunction之后,存在一个临时字符串对象。什么时候超出范围?

严格来说,它永远不会范围内。范围是名称的属性,而不是对象。事实上,自动变量在范围生命周期之间具有非常紧密的关联。非自动变量的对象是不同的。

临时对象在它们出现的完整表达式的末尾被销毁,但有一些与此无关的例外。无论如何,特殊情况延长临时的生命周期,他们不会减少它。

  

编译器是否可以调用c_str(),破坏此临时字符串对象,然后将悬空指针传递给LegacyFunction

不,因为全表达式是LegacyFunction(ModernFunction().c_str())(不包括分号:感觉那个迂腐),所以ModernFunction的临时值不会被销毁LegacyFunction已经回来了。

  

如果安全,为什么?

因为临时的寿命足够长。

一般情况下c_str,你必须担心两件事。首先,如果字符串被销毁,它返回的指针将变为无效(这就是你所要求的)。其次,如果修改了字符串,它返回的指针将变为无效。你没有在这担心,但没关系,因为没有修改字符串。