C++临时变量的生命周期

5

这段代码是否有效?

int foo()
{
    std::vector<std::string>& v = std::vector<std::string>(5, "X");

    // Do something silly...

    return 42;
}

由于某种原因,我认为临时的std::vector对象(紧接着赋值符号)在它的构造后就应该被销毁(从而使引用无效)
然而,调试证明我是错误的,我意识到我不太理解为什么当函数返回时,临时变量会被销毁。
我想我对一些基本的东西有一个强烈的误解,请给我普及一下 :)

当你说“调试证明我是错的”时,你到底是什么意思? - Oliver Charlesworth
3个回答

8
您展示的代码是不合法的 - 临时对象只能绑定到右值引用或const左值引用。
VC++允许这种做法作为扩展(并给出级别4警告以此说明)。

1
gcc会友好地报错:error: invalid initialization of non-const reference of type 'std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > >&' from a temporary of type 'std::vector<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::allocator<std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > - Scottymac
谢谢,我不知道那个扩展 *(而且,我应该尝试一下 gcc)*。 - Yippie-Ki-Yay
2
@Yippie-Kai-Yay:那你应该启用级别4的警告来构建。;-] - ildjarn
6
请注意,如果它是一个const引用,那么是合法的。对于const引用,临时变量的寿命会被延长到const引用的寿命,这恰好是函数结束的时间。 - Sjoerd
@ildjarn 可能我应该这样做 :) 但是,实现一些功能并针对标准进行调用并将它们称为“扩展”的根本原因是什么?遗留代码问题吗? - Yippie-Ki-Yay
4
在这种情况下,确实是这样 - VC ++的框架(MFC / ATL)滥用了此扩展。请注意,C ++标准明确地“允许”语言扩展,以使本来不符合规范的代码能够编译,“只要编译器发出诊断”(在这种情况下为警告)。您没有看到警告,因为默认警告级别为3。 :-] - ildjarn

3

临时变量的正常生命周期是在创建它的完整表达式结束时终止;它不一定会立即在使用后被销毁。如果这个临时变量用于初始化一个引用,它的生命周期将被扩展以匹配该引用的生命周期(但构造函数初始化列表中创建的临时变量除外)。

当然,你的代码是非法的;如果引用是非const类型,它只能用某种左值进行初始化。但如果它是合法的(至少有一个编译器接受它),那么生命周期应该被扩展以匹配引用的生命周期。


2
你有一个已释放的对象的引用。它能够“奇迹般”地工作(参见《C++程序设计语言》第10.4.10节临时对象)。你不能保证它在每个编译器中都能正常工作。
只有当临时对象被绑定到一个const引用时,你才能确保其生命周期得到延长。

2
这并不是纯粹的运气,而是由编译器提供的语言扩展。 - ildjarn
@ildjarn,我只是在开玩笑地引用Stroustrup的话。重点是它是不可移植/非法/不可靠或者你想怎么称呼它都可以。 - frozenkoi
3
同意,它不具备可移植性,但也不违法。C++标准(§1.4/8)明确允许语言扩展,只要扩展不影响正确编写的代码行为,并且编译器发出诊断信息(警告计数)。 - ildjarn
请注意,当标准讨论临时对象的生命周期时,它谈到了延长绑定到引用的临时对象的生命周期。它并没有提到是否为const。因此,从逻辑上讲,如果编译器接受使用临时对象初始化非const引用,它也将延长临时对象的生命周期。 - James Kanze

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接