<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="zh-Hans-CN">
	<id>https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=C%2B%2B_NRVO</id>
	<title>C++ NRVO - 版本历史</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.riguz.com/index.php?action=history&amp;feed=atom&amp;title=C%2B%2B_NRVO"/>
	<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=C%2B%2B_NRVO&amp;action=history"/>
	<updated>2026-06-02T22:45:16Z</updated>
	<subtitle>本wiki上该页面的版本历史</subtitle>
	<generator>MediaWiki 1.42.3</generator>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=C%2B%2B_NRVO&amp;diff=3765&amp;oldid=prev</id>
		<title>Riguz：​Riguz移动页面Blog:C++中的NRVO至C++ NRVO，不留重定向</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=C%2B%2B_NRVO&amp;diff=3765&amp;oldid=prev"/>
		<updated>2023-12-19T05:52:08Z</updated>

		<summary type="html">&lt;p&gt;Riguz移动页面&lt;a href=&quot;/index.php?title=Blog:C%2B%2B%E4%B8%AD%E7%9A%84NRVO&amp;amp;action=edit&amp;amp;redlink=1&quot; class=&quot;new&quot; title=&quot;Blog:C++中的NRVO（页面不存在）&quot;&gt;Blog:C++中的NRVO&lt;/a&gt;至&lt;a href=&quot;/C%2B%2B_NRVO&quot; title=&quot;C++ NRVO&quot;&gt;C++ NRVO&lt;/a&gt;，不留重定向&lt;/p&gt;
&lt;table style=&quot;background-color: #fff; color: #202122;&quot; data-mw=&quot;interface&quot;&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;col class=&quot;diff-marker&quot; /&gt;
				&lt;col class=&quot;diff-content&quot; /&gt;
				&lt;tr class=&quot;diff-title&quot; lang=&quot;zh-Hans-CN&quot;&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;←上一版本&lt;/td&gt;
				&lt;td colspan=&quot;2&quot; style=&quot;background-color: #fff; color: #202122; text-align: center;&quot;&gt;2023年12月19日 (二) 05:52的版本&lt;/td&gt;
				&lt;/tr&gt;&lt;tr&gt;&lt;td colspan=&quot;4&quot; class=&quot;diff-notice&quot; lang=&quot;zh-Hans-CN&quot;&gt;&lt;div class=&quot;mw-diff-empty&quot;&gt;（没有差异）&lt;/div&gt;
&lt;/td&gt;&lt;/tr&gt;
&lt;!-- diff cache key wiki_db:diff:1.41:old-2662:rev-3765 --&gt;
&lt;/table&gt;</summary>
		<author><name>Riguz</name></author>
	</entry>
	<entry>
		<id>https://wiki.riguz.com/index.php?title=C%2B%2B_NRVO&amp;diff=2662&amp;oldid=prev</id>
		<title>imported&gt;Riguz：​对于C++这种需要精细管理对象的语言来说有时候真是比较复杂，一个看似简单的问题一直在困惑着我：到底可不可以在方法中返回局部变量呢？</title>
		<link rel="alternate" type="text/html" href="https://wiki.riguz.com/index.php?title=C%2B%2B_NRVO&amp;diff=2662&amp;oldid=prev"/>
		<updated>2019-09-25T00:00:00Z</updated>

		<summary type="html">&lt;p&gt;对于C++这种需要精细管理对象的语言来说有时候真是比较复杂，一个看似简单的问题一直在困惑着我：到底可不可以在方法中返回局部变量呢？&lt;/p&gt;
&lt;p&gt;&lt;b&gt;新页面&lt;/b&gt;&lt;/p&gt;&lt;div&gt;对于C++这种需要精细管理对象的语言来说有时候真是比较复杂，一个看似简单的问题一直在困惑着我：到底可不可以在方法中返回局部变量呢？&lt;br /&gt;
&lt;br /&gt;
= 可以返回临时变量=&lt;br /&gt;
&lt;br /&gt;
答案是肯定的，如果我们在一个方法中返回了临时变量，这个临时变量实际上是在栈里面的，当执行完方法后栈就销毁了，那么为什么我们还可以这样做呢？来看一个例子：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
#include &amp;lt;iostream&amp;gt;&lt;br /&gt;
using namespace std;&lt;br /&gt;
&lt;br /&gt;
class Value {&lt;br /&gt;
    public:&lt;br /&gt;
        Value(int _m):m(_m) { std::cout &amp;lt;&amp;lt; &amp;quot;test constructor&amp;quot; &amp;lt;&amp;lt; m &amp;lt;&amp;lt; std::endl; }&lt;br /&gt;
        Value(const Value&amp;amp; t) { &lt;br /&gt;
            std::cout &amp;lt;&amp;lt; &amp;quot;test copy constructor&amp;quot; &amp;lt;&amp;lt; m &amp;lt;&amp;lt; std::endl; &lt;br /&gt;
            this-&amp;gt;m = t.m;&lt;br /&gt;
        }&lt;br /&gt;
        ~Value() { std::cout &amp;lt;&amp;lt; &amp;quot;test destructor&amp;quot; &amp;lt;&amp;lt; m &amp;lt;&amp;lt; std::endl; }&lt;br /&gt;
        void print() { std::cout &amp;lt;&amp;lt; &amp;quot;m:&amp;quot; &amp;lt;&amp;lt; m &amp;lt;&amp;lt; std::endl; }&lt;br /&gt;
    private:&lt;br /&gt;
        int m;&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
class Producer {&lt;br /&gt;
public:&lt;br /&gt;
    Value produce(int i) {&lt;br /&gt;
        Value t(i);&lt;br /&gt;
        return t;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&lt;br /&gt;
int main(int argc, char* argv[]) {&lt;br /&gt;
    std::cout &amp;lt;&amp;lt; &amp;quot;Hello world!&amp;quot; &amp;lt;&amp;lt; std::endl;&lt;br /&gt;
    Producer p;&lt;br /&gt;
    Value t = p.produce(100);&lt;br /&gt;
    t.print();&lt;br /&gt;
    return 1;&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
执行的结果是：&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
Hello world!&lt;br /&gt;
test constructor100&lt;br /&gt;
m:100&lt;br /&gt;
test destructor100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
结果证明这样做其实是可以取到我们定义的值的，这么做可行的原因是，实际上，编译器会帮我们把临时变量拷贝一份出来，所以即便栈销毁了，我们也能够拿到新的值。&lt;br /&gt;
&lt;br /&gt;
= 不要返回临时变量的引用=&lt;br /&gt;
&lt;br /&gt;
那么，如果我们返回临时变量的引用呢？&lt;br /&gt;
&amp;lt;syntaxhighlight lang=&amp;quot;c++&amp;quot;&amp;gt;&lt;br /&gt;
class Producer {&lt;br /&gt;
public:&lt;br /&gt;
    Value* produce(int i){&lt;br /&gt;
        Value t(i);&lt;br /&gt;
        return &amp;amp;t;&lt;br /&gt;
    }&lt;br /&gt;
};&lt;br /&gt;
&amp;lt;/syntaxhighlight&amp;gt;&lt;br /&gt;
这样做得到的结果是不对的：&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
test.cpp:21:17: warning: address of stack memory associated with local variable &amp;#039;t&amp;#039; returned [-Wreturn-stack-address]&lt;br /&gt;
        return &amp;amp;t;&lt;br /&gt;
                ^&lt;br /&gt;
1 warning generated.&lt;br /&gt;
Hello world!&lt;br /&gt;
test constructor100&lt;br /&gt;
test destructor100&lt;br /&gt;
m:-327065280&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
编译器会有一个警告，尽管我们仍旧可以运行我们的代码，但是实际上我们得到的值是不对的。&lt;br /&gt;
&lt;br /&gt;
= NRVO机制=&lt;br /&gt;
那么，既然我们返回临时对象的值，实际上会得到一个拷贝的对象，那么如果我们有拷贝构造函数，是不是应该被调用呢？&lt;br /&gt;
&lt;br /&gt;
然而在前面的例子中，拷贝构造函数并没有被调用到，这又是为什么呢？答案就是因为NRVO(Return Value Optimization)。这是c++11中的特性。我们首先可以尝试禁用掉这个特性，看看会发生什么。&lt;br /&gt;
&lt;br /&gt;
&amp;lt;pre&amp;gt;&lt;br /&gt;
hfli@CNhfli ~ $ g++ -fno-elide-constructors test.cpp&lt;br /&gt;
hfli@CNhfli ~ $ ./a.out&lt;br /&gt;
Hello world!&lt;br /&gt;
test constructor100&lt;br /&gt;
test copy constructor0&lt;br /&gt;
test destructor100&lt;br /&gt;
test copy constructor0&lt;br /&gt;
test destructor100&lt;br /&gt;
m:100&lt;br /&gt;
test destructor100&lt;br /&gt;
&amp;lt;/pre&amp;gt;&lt;br /&gt;
可以看出，拷贝构造函数调用了两次，第一次是在produce函数中返回的时候，第二次是我们在给变量赋值的时候。&lt;/div&gt;</summary>
		<author><name>imported&gt;Riguz</name></author>
	</entry>
</feed>