Стоит ли повсеместно стараться как можно чаще использовать r-value ссылки? Вот, допустим, код:
std::string hi() {
return "hello world
"
}
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
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
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;
}
Комментариев нет:
Отправить комментарий