<?xml version="1.0" encoding="utf-8"?>

<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
	<channel>
		<title>Форум программистов и сисадминов Киберфорум - Блоги - soon</title>
		<link>https://www.cyberforum.ru/blogs/174410/</link>
		<description>КиберФорум - форум программистов, системных администраторов, администраторов баз данных, компьютерный форум, форум по электронике и бытовой технике, обсуждение софта. Бесплатная помощь в решении задач по программированию и наукам, решение проблем с компьютером, операционными системам</description>
		<language>ru</language>
		<lastBuildDate>Sat, 05 Sep 2026 10:12:37 GMT</lastBuildDate>
		<generator>vBulletin</generator>
		<ttl>60</ttl>
		<image>
			<url>https://www.cyberforum.ru//cyberstatic.net/images/misc/rss.jpg</url>
			<title>Форум программистов и сисадминов Киберфорум - Блоги - soon</title>
			<link>https://www.cyberforum.ru/blogs/174410/</link>
		</image>
		<item>
			<title>Семантика перемещения и perfect forwarding(правильная передача)</title>
			<link>https://www.cyberforum.ru/blogs/174410/826.html</link>
			<pubDate>Thu, 18 Oct 2012 15:14:31 GMT</pubDate>
			<description>По стандарту С++, временный объект можно передавать в функцию только по константной ссылке. Это...</description>
			<content:encoded><![CDATA[<div>По стандарту С++, временный объект можно передавать в функцию только по константной ссылке. Это вызывало некоторые осложнения, поскольку временный объект был неотличим от константного объекта, как следствие, было неясно, надо-ли сохранять объект или можно просто его просто переместить. Стандарт <b>C++11</b> представляет новый вид ссылки - <i>rvalue reference</i> - ссылка на временный объект. Как и обычная ссылка, она может быть <i>const</i> и <i>non-const</i>. Как и обычная ссылка, она должна быть инициализирована при объявлении.<br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="185538761"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="185538761" style="height: 270px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
</pre></td><td class="de1"><pre class="de1"><span class="kw4">int</span> foo<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">int</span> a <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> a<span class="sy4">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&amp;&amp;</span> a <span class="sy1">=</span> foo<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="co1">// a = foo(); // Error</span>
&nbsp;
&nbsp; &nbsp; <span class="kw4">int</span><span class="sy3">&amp;&amp;</span> b <span class="sy1">=</span> foo<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; b <span class="sy1">=</span> foo<span class="br0">&#40;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Вернемся чуть позже к вопросу о возвращаемом типе.<br />
<br />
<b>std::move()</b><br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="334932965"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="334932965" style="height: 110px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
</pre></td><td class="de1"><pre class="de1"><span class="kw2">template</span> <span class="sy1">&lt;</span><span class="kw2">class</span> T<span class="sy1">&gt;</span>
std<span class="sy4">::</span><span class="me2">remove_reference</span><span class="sy1">&lt;</span>T<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">type</span><span class="sy3">&amp;&amp;</span> move<span class="br0">&#40;</span>T<span class="sy3">&amp;&amp;</span> t<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="kw2">static_cast</span><span class="sy1">&lt;</span><span class="kw2">typename</span> std<span class="sy4">::</span><span class="me2">remove_reference</span><span class="sy1">&lt;</span>T<span class="sy1">&gt;</span><span class="sy4">::</span><span class="me2">type</span><span class="sy3">&amp;&amp;</span><span class="sy1">&gt;</span><span class="br0">&#40;</span>t<span class="br0">&#41;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как видим, <i>std::move</i> не делает ничего, кроме преобразования типа. В этом и заключается особенность перемещения - мы лишь сигнализируем о том, что данные в объекте нам больше не нужны. Взглянем на пример<br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="235963552"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="235963552" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
</pre></td><td class="de1"><pre class="de1"><span class="kw2">class</span> Foo
<span class="br0">&#123;</span>
&nbsp; &nbsp; <span class="kw4">int</span><span class="sy2">*</span> _arr<span class="sy4">;</span>
&nbsp;
<span class="kw2">public</span><span class="sy4">:</span>
&nbsp; &nbsp; Foo<span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; _arr <span class="sy1">=</span> <span class="kw3">new</span> <span class="kw4">int</span><span class="br0">&#91;</span><span class="nu0">1024</span><span class="br0">&#93;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; Foo<span class="br0">&#40;</span>Foo<span class="sy3">&amp;&amp;</span> f<span class="br0">&#41;</span><span class="sy4">:</span> _arr<span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">&#40;</span>f._arr<span class="br0">&#41;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp;
&nbsp; &nbsp; <span class="br0">&#125;</span>
&nbsp;
&nbsp; &nbsp; ~Foo<span class="br0">&#40;</span><span class="br0">&#41;</span>
&nbsp; &nbsp; <span class="br0">&#123;</span>
&nbsp; &nbsp; &nbsp; &nbsp; <span class="kw3">delete</span><span class="br0">&#91;</span><span class="br0">&#93;</span> _arr<span class="sy4">;</span>
&nbsp; &nbsp; <span class="br0">&#125;</span>
<span class="br0">&#125;</span><span class="sy4">;</span>
&nbsp;
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; Foo f1<span class="sy4">;</span>
&nbsp; &nbsp; Foo f2<span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">&#40;</span>f1<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Опа! Glibc detected. Все дело в том, что f1._arr и f2._arr указывают на одну область памяти. Итак, что я пытался этим донести. Первое, <i>std::move</i> только возвращает <i>rvalue reference</i> на переданный аргумент. Ничего не стирается. Второе, если явно выделяется память, то нужно проследить за корректным ее освобождением. Пример выше правится добавлением<br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="814992758"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="814992758" style="height: 46px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
</pre></td><td class="de1"><pre class="de1">f._arr <span class="sy1">=</span> <span class="kw2">nullptr</span><span class="sy4">;</span></pre></td></tr></table></div></td></tr></tbody></table></div>в перемещающий конструктор.<br />
<br />
Теперь к вопросу о возвращаемом типе. Как уже было сказано, <i>rvalue reference</i> по-прежнему ссылка. Следовательно, никогда не возвращайте <i>rvalue reference</i> на локальную переменную. Стандарт гарантирует вызов перемещающего конструктора, если он определен и нет оптимизаций со стороны компилятора. В противном случае, будет вызван копирующий конструктор, либо, при его отсутствии, будет ошибка времени компиляции.<br />
<br />
Также следует помнить, что даже при передаче <i>rvalue reference</i> в копирующий конструктор(к примеру), все его члены(исключение, пожалуй, могут составить примитивные типы, поскольку разницы между копированием / перемещением там нет) необходимо явно приводить к <i>rvalue reference</i>, чтобы не был вызван конструктор копирования. Это касается, в том числе, передачи полученного аргумента в другие функции. Объясняется это тем, что за <i>rvalue reference</i> скрываются реально существующие данные, которые абсолютно точно уверены в том, что они lvalue, а следовательно, и ведут себя как lvalue. Однако, бывают ситуации, когда мы не можем утверждать, что передан <i>T&amp;&amp;</i>, а не <i>rvalue reference на T&amp;</i>. Да-да, шаблонная &quot;магия&quot;<br />
<br />
<b>Perfect Forwarding</b><br />
<br />
Взглянем на код<br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="715713648"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="715713648" style="height: 350px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
</pre></td><td class="de1"><pre class="de1"><span class="kw4">void</span> foo<span class="br0">&#40;</span><span class="kw4">const</span> <span class="kw4">int</span><span class="sy3">&amp;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot;Hello! I'm foo(const int&amp;)&quot;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw4">void</span> foo<span class="br0">&#40;</span><span class="kw4">int</span><span class="sy3">&amp;&amp;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot;Hello! I'm foo(int&amp;&amp;)&quot;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw2">template</span> <span class="sy1">&lt;</span><span class="kw2">class</span> T<span class="sy1">&gt;</span>
<span class="kw4">void</span> bar<span class="br0">&#40;</span>T<span class="sy3">&amp;&amp;</span> t<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot;Hello! I'm bar&lt;T&gt;(T&amp;&amp;)&quot;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span>
&nbsp; &nbsp; foo<span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">move</span><span class="br0">&#40;</span>t<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
<span class="br0">&#125;</span>
&nbsp;
<span class="kw4">int</span> main<span class="br0">&#40;</span><span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; bar<span class="br0">&#40;</span><span class="nu0">42</span><span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp;
&nbsp; &nbsp; <span class="kw4">int</span> a <span class="sy1">=</span> <span class="nu0">42</span><span class="sy4">;</span>
&nbsp; &nbsp; bar<span class="br0">&#40;</span>a<span class="br0">&#41;</span><span class="sy4">;</span>
&nbsp;
&nbsp; &nbsp; <span class="kw1">return</span> <span class="nu0">0</span><span class="sy4">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Как я уже сказал выше, во втором случае шаблон инстанцируется с типом <i>rvalue reference на reference</i>. В этом случае на сцену выходит <i>std::forward&lt;T&gt;</i>. Его функции просты - передать объект далее, сохраняя его тип. Если переписать функцию <i>bar(T&amp;&amp;)</i>, то мы получим то, что и ожидали увидеть с самого начала.<br />
<div class="codeblock"><table class="cpp"><thead><tr><td colspan="2" id="663990001"  class="head">C++</td></tr></thead><tbody><tr class="li1"><td><div id="663990001" style="height: 126px" class="codeframe"><table><tr class="li1"><td class="ln" style="padding: 0px 10px 0px 5px;"><pre class="de1">1
2
3
4
5
6
</pre></td><td class="de1"><pre class="de1"><span class="kw2">template</span> <span class="sy1">&lt;</span><span class="kw2">class</span> T<span class="sy1">&gt;</span>
<span class="kw4">void</span> bar<span class="br0">&#40;</span>T<span class="sy3">&amp;&amp;</span> t<span class="br0">&#41;</span>
<span class="br0">&#123;</span>
&nbsp; &nbsp; std<span class="sy4">::</span><span class="kw3">cout</span> <span class="sy1">&lt;&lt;</span> <span class="st0">&quot;Hello! I'm bar&lt;T&gt;(T&amp;&amp;)&quot;</span> <span class="sy1">&lt;&lt;</span> std<span class="sy4">::</span><span class="me2">endl</span><span class="sy4">;</span>
&nbsp; &nbsp; foo<span class="br0">&#40;</span>std<span class="sy4">::</span><span class="me2">forward</span><span class="sy1">&lt;</span>T<span class="sy1">&gt;</span><span class="br0">&#40;</span>t<span class="br0">&#41;</span><span class="br0">&#41;</span><span class="sy4">;</span>
<span class="br0">&#125;</span></pre></td></tr></table></div></td></tr></tbody></table></div>Теперь, при вызове <i>bar&lt;int&amp;&gt;</i> будет вызвана функция <i>foo(const int&amp;)</i>, а при вызове <i>bar&lt;int&gt;</i> - <i>foo(int&amp;&amp;)</i></div>

]]></content:encoded>
			<dc:creator>soon</dc:creator>
			<guid isPermaLink="true">https://www.cyberforum.ru/blogs/174410/826.html</guid>
		</item>
	</channel>
</rss>
