Стоит ли повсеместно стараться как можно чаще использовать r-value ссылки? Вот, допустим, код:
std::string hi() {
return "hello world\n"
}
auto&& str = hi();
В данном случае в строке 5 происходит лишь одно создание объекта, и r-value ссылка на него, и никакого копирования... эффективно, если сравнить, например, с:
auto str = hi();
или
auto str = std::move(hi());
Посему на первый взгляд напрашивается вывод: почему бы не создавать r-value ссылки как можно чаще вместо обычной инициализации переменной? Особенно если нужно создавать 100000 раз в секунду эти переменные. Допустим, если можно, то писать так:
void function() {
int&& a = 1;
double&& b = 2.;
auto&& value = return_value();
/*далее какой-то код*/
}
и далее работать с этими ссылками или передавать их в другое место... выглядит, это чуть более монстрообразно, чем обычная инициализация переменных, к которой глаз привык:
void function() {
int a = 1;
double b = 2.;
auto value = return_value();
/*далее какой-то код*/
}
Поэтому стоит ли как можно чаще пользоваться r-value ссылками вместо обычной инициализации новых переменных в локальном контексте(внутри функций, например) для эффективности, или есть ли какие-то встроенные оптимизации, которые при int a = 2
делают те же действия, что и int&& a = 2
?
Обычно ссылки хранятся в памяти в виде указателей на объекты. Поэтому в данном предложении
auto &&a = 1;
будет создан временный объект со значением 1
и ссылка на него.
Если у вас есть объявление вида
auto a = f();
где функция f
возвращает объект некоторого типа T
, то этот объект, возвращаемый из функции, строится на месте переменной a
, минуя вызов копирующего или перемещающего конструктора.
Рассмотрите следующий пример
#include <iostream>
struct Int
{
Int( int x = 0 ) : x( x )
{
std::cout << "Int::Int( int )" << std::endl;
}
Int( const Int &rhs ) : x( rhs.x )
{
std::cout << "Int::Int( const Int & )" << std::endl;
}
Int( Int &&rhs ) : x( rhs.x )
{
std::cout << "Int::Int( Int && )" << std::endl;
}
~Int()
{
std::cout << "Int::~Int()" << std::endl;
}
int x;
};
Int f( int x ) { return x; }
int main()
{
auto x = f( 10 );
auto &&y = f( 20 );
return 0;
}
Вывод на консоль будет следующим
Int::Int( int )
Int::Int( int )
Int::~Int()
Int::~Int()
То есть в обоих случаях будет вызвано по одному конструктору и, соответственно, деструктору.
К тому же нельзя создавать, например, массивы из ссылок. В нижеприведенной программе, если раскомментировать предложение с массивом ссылок, то будет выдано сообщение об ошибке.
#include <iostream>
struct Int
{
Int( int x = 0 ) : x( x )
{
std::cout << "Int::Int( int )" << std::endl;
}
Int( const Int &rhs ) : x( rhs.x )
{
std::cout << "Int::Int( const Int & )" << std::endl;
}
Int( Int &&rhs ) : x( rhs.x )
{
std::cout << "Int::Int( Int && )" << std::endl;
}
~Int()
{
std::cout << "Int::~Int()" << std::endl;
}
int x;
};
Int f( int x ) { return x; }
int main()
{
Int a[] = { f( 10 ) };
//Int &&b[] = { f( 10 ) };
return 0;
}
На самом деле доступ к переменной напрямую всегда быстрее чем по ссылке. Составим простую программу:
int O() {
int x = 5;
return x;
}
int test(){
auto&& value = O();
return value;
}
int test2(){
auto value = O();
return value;
}
Соберём БЕЗ оптимизаций.
test():
push rbp
mov rbp, rsp
sub rsp, 16
call O()
mov DWORD PTR [rbp-12], eax
lea rax, [rbp-12]
mov QWORD PTR [rbp-8], rax
mov rax, QWORD PTR [rbp-8]
mov eax, DWORD PTR [rax]
leave
ret
test2():
push rbp
mov rbp, rsp
sub rsp, 16
call O()
mov DWORD PTR [rbp-4], eax
mov eax, DWORD PTR [rbp-4]
leave
ret
Как видите работа напрямую - меньше операций сразу, хотя мы переменную и не использовали считай. В общем для примитивов однозначно лучше переменная, для сложных классов - воспользуйтесь профайлером (возможно есть смысл использовать перемещающий конструктор или что-то такое).
В данном случае нет никакой практической разницы между
auto str = hi();
и
auto&& str = hi();
В обоих случаях copy elision и return value optimization приводят к тому, что результат функции hi
будет формироваться (конструироваться) напрямую в финальном объекте. В первом случае - напрямую в str
. Во-втором случае - напрямую во временном объекте, к которому будет привязываться str
.
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Доброе время суток! У меня есть проект на Python35, а именно система автоматического тестирования для локальной сети(тестер для олимпиадных задач...
Объясните, пожалуйста, как тут создается структура? Что делает знак двоеточие :?