0 added
0 removed
Original
2026-01-01
Modified
2026-03-10
1
<p>Теги: copy/move elision, универсальные ссылки</p>
1
<p>Теги: copy/move elision, универсальные ссылки</p>
2
<p>Copy/move elision представляет собой оптимизацию, когда компилятор может убрать определенные вызовы конструктора копирования и деструктора, но только при возврате объекта из функции и если тип возвращаемого объекта совпадает с типом функции.</p>
2
<p>Copy/move elision представляет собой оптимизацию, когда компилятор может убрать определенные вызовы конструктора копирования и деструктора, но только при возврате объекта из функции и если тип возвращаемого объекта совпадает с типом функции.</p>
3
<p>В результате при возврате из функции применение<a>std::move()</a>способно понизить производительность, ограничив тем самым компилятор в Copy elision оптимизации, ведь отсутствие конструктора, по сути, быстрее, чем конструктор перемещения.</p>
3
<p>В результате при возврате из функции применение<a>std::move()</a>способно понизить производительность, ограничив тем самым компилятор в Copy elision оптимизации, ведь отсутствие конструктора, по сути, быстрее, чем конструктор перемещения.</p>
4
<p>В данном случае std::move() лишь замедляет код, добавляя излишний вызов String(String&& other) и ~String(). При этом стоит учесть, что в C++20 copy/move elision может быть расширен, в результате чего в ряде случаев применение std::move() тоже снизит производительность.</p>
4
<p>В данном случае std::move() лишь замедляет код, добавляя излишний вызов String(String&& other) и ~String(). При этом стоит учесть, что в C++20 copy/move elision может быть расширен, в результате чего в ряде случаев применение std::move() тоже снизит производительность.</p>
5
<h2>Универсальные ссылки</h2>
5
<h2>Универсальные ссылки</h2>
6
<p>Вернувшись к теме одной из<a>предыдущих статей</a>, скажем, что универсальные ссылки способны быть как rvalue-, так и lvalue-ссылкой - это зависит от аргументов либо результата функции. Применяются они в шаблонах и в auto&&:</p>
6
<p>Вернувшись к теме одной из<a>предыдущих статей</a>, скажем, что универсальные ссылки способны быть как rvalue-, так и lvalue-ссылкой - это зависит от аргументов либо результата функции. Применяются они в шаблонах и в auto&&:</p>
7
<p>На основе данного шаблона компилятор генерирует две функции, причем одна из них принимает lvalue, а вторая - rvalue, если они будут применяться. Когда разработчик желает использовать перемещение для rvalue-ссылки и обычное простое копирование для lvalue-ссылки, он может применить std::forward(), приводящий свой аргумент к rvalue лишь тогда, когда его тип - это rvalue-ссылка. Что касается std::forward(), то он требует явного указания шаблонного параметра.</p>
7
<p>На основе данного шаблона компилятор генерирует две функции, причем одна из них принимает lvalue, а вторая - rvalue, если они будут применяться. Когда разработчик желает использовать перемещение для rvalue-ссылки и обычное простое копирование для lvalue-ссылки, он может применить std::forward(), приводящий свой аргумент к rvalue лишь тогда, когда его тип - это rvalue-ссылка. Что касается std::forward(), то он требует явного указания шаблонного параметра.</p>
8
<p>Собственно говоря, универсальная ссылка просто обязана быть шаблонным параметром, откуда в нашем примере и взялось странное определение шаблона функции в формате T&&. Таким образом, std::vector<T>&& - это уже не универсальная ссылка, а rvalue-ссылка.</p>
8
<p>Собственно говоря, универсальная ссылка просто обязана быть шаблонным параметром, откуда в нашем примере и взялось странное определение шаблона функции в формате T&&. Таким образом, std::vector<T>&& - это уже не универсальная ссылка, а rvalue-ссылка.</p>
9
<p>Но вообще, особой разницы между универсальной и rvalue-ссылкой не существует. Можно сказать, что универсальная ссылка является лишь удобной абстракцией над rvalue-ссылкой, которой, как раз таки, многие и пользуются. Но как же тогда rvalue-ссылка превращается в lvalue-ссылку, имея lvalue-аргумент? Ответ - путем свертывания ссылок.</p>
9
<p>Но вообще, особой разницы между универсальной и rvalue-ссылкой не существует. Можно сказать, что универсальная ссылка является лишь удобной абстракцией над rvalue-ссылкой, которой, как раз таки, многие и пользуются. Но как же тогда rvalue-ссылка превращается в lvalue-ссылку, имея lvalue-аргумент? Ответ - путем свертывания ссылок.</p>
10
<p>Когда происходит вызов template_func(string), компилятор генерирует следующий заголовок функции:</p>
10
<p>Когда происходит вызов template_func(string), компилятор генерирует следующий заголовок функции:</p>
11
<p>Таким образом, получается ссылка на ссылку! Сделать так вручную невозможно, однако шаблоны могут. Потом компилятор свертывает ссылку на ссылку, а происходит это по определенному правилу: результатом свертывания становится rvalue-ссылка, но лишь в том случае, если обе ссылки - это rvalue-ссылки. И, как раз из-за данного безобразия и проще применять абстракцию универсальных ссылок.</p>
11
<p>Таким образом, получается ссылка на ссылку! Сделать так вручную невозможно, однако шаблоны могут. Потом компилятор свертывает ссылку на ссылку, а происходит это по определенному правилу: результатом свертывания становится rvalue-ссылка, но лишь в том случае, если обе ссылки - это rvalue-ссылки. И, как раз из-за данного безобразия и проще применять абстракцию универсальных ссылок.</p>
12
<p><em><a>Источник</a></em></p>
12
<p><em><a>Источник</a></em></p>
13
13