2012-09-07 29 views
17

可能重复:
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. 如果上面的代码不安全,为什么它不安全,并且有没有更好,同样简洁的写法它比进行函数调用时添加一个临时变量?如果安全,为什么?
+0

我刚刚编译这个,它的工作。根据ForEveR的回答,它也应该起作用。 – 2012-09-07 17:59:27

+2

@ H2CO3,“它的工作”从来没有证明任何东西 - 有时你只是幸运。如果你已经尝试过它,它*不工作,那就会有所不同。 –

+0

@MarkRansom注意到“它也应该工作,根据ForEveR的答案”部分? (澄清:我知道) – 2012-09-07 18:04:23

回答

14
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 
{ } 
} 

9

有ModernFunction返回之后存在的临时字符串对象。它何时超出范围?

严格来说,从来没有范围内。范围是名称的属性,而不是对象。恰巧恰巧自动变量在范围生存期之间有非常密切的关联。不是自动变量的对象是不同的。

临时对象在它们出现的完整表达式的末尾被销毁,其中有几个例外与此处不相关。无论如何,特殊情况下延伸临时的一生,他们不减少它。

是否有可能为编译器调用c_str(),破坏此临时字符串对象,然后通过悬空指针LegacyFunction

没有,因为全表达是LegacyFunction(ModernFunction().c_str())(不包括分号:感觉是pedantry),所以临时的ModernFunction的返回值不会被销毁,直到LegacyFunction已经返回。

如果安全,为什么?

因为临时的寿命足够长。

通常与c_str,你不得不担心两件事情。首先,如果字符串被销毁(这就是你所要求的),它返回的指针变为无效。其次,如果字符串被修改,它返回的指针变为无效。这里你不担心,但没关系,你不需要,因为没有任何修改字符串。