Я хочу передать структуру по ссылке, чтобы она не была скопирована, но Resharper выдает предупреждение ниже:
struct sometype {
};
sometype foo() {
sometype x;
return x;
}
void bar() {
sometype & a = foo();//Binding r-value to l-value reference is non-standard Microsoft C++ extension
sometype && b = foo(); //ok
}
Вопросы:
Что случилось с sometype & a = foo();
? не возвращаемое значение из foo()
lvalue и a
тоже lvalue?
Является sometype && b = foo();
на самом деле rvalue ссылка? Это «украсть» возвращаемое значение из foo()
и отправить то, что было в b
деструктору?
Есть ли другой способ не иметь это предупреждение?
Вы берете ссылку на временный объект. Единственный законный способ сделать это:
const object&
(ссылка на постоянное l-значение) или
object&&
(изменяемая ссылка r-значения)
Это (преднамеренное) ограничение языка.
дальнейшее обсуждение:
Присвоение временного объекта ссылке увеличивает время жизни временного объекта, чтобы оно соответствовало времени существования ссылки. Поэтому, к удивлению многих начинающих, это законно:
{
const string& s = foo();
cout << s << endl; // the temporary to which s refers is still alive
}
// but now it's destroyed
Однако, как правило, было бы логичной ошибкой брать изменяемую ссылку на временную ссылку, так что это запрещено на языке:
{
string s& = foo(); // this is not possible
s += "bar"; // therefore neither is this
// the implication is that since you modified s, you probably want to
// preserve it
}
// ... but now it's destroyed and you did nothing with it.
вот более реалистичная причина, почему это, вероятно, логическая ошибка, учитывая:
string foo(); // function returning a string
void bar(string& s); // this function is asserting that it intends to *modify*
// the string you sent it
// therefore:
bar(foo()); // makes no sense. bar is modifying a string that will be discarded.
// therefore assumed to be a logic error
Вы должны заменить вышеуказанное на:
string s = foo();
s += "bar";
// do something here with s
Обратите внимание, что нет никаких издержек для захвата временного в именованной переменной (l-значение).
Ссылки на r-значения предназначены для объекта-конструктора перемещения или присвоения-перемещения. Поэтому имеет смысл, что они изменчивы. Сама их природа подразумевает, что объект временный.
Таким образом, это законно:
string&& s = foo(); // extends lifetime as before
s += "bar";
baz(std::move(s)); // move the temporary into the baz function.
Это может помочь вам запомнить это указание &&
ты утверждаешь, что ты знать что переменная является изменяемой временной.
Но настоящая причина, по которой это разрешено, заключается в том, что это будет работать:
string foo(); // function that returns a string
void bar(string&& s); // function that takes ownership of s
bar(foo()); // get a string from foo and move it into bar
// or more verbosely:
string s = foo();
bar(move(s));
до c ++ 11 бар должен был быть написан одним из следующих способов:
void bar(string s); // copy a string
// resulting in:
const string& s = foo();
bar(s); // extra redundant copy made here
void bar(const string& s); // const l-value reference - we *may* copy it
// resulting in:
const string& s = foo();
bar(s); // maybe an extra redundant copy made here, it's up to bar().
Что не так с sometype & a = foo (); ?
foo () возвращает временное значение, поэтому вы не можете связать его со ссылкой, так как он больше не будет существовать после окончания полного выражения (строки присваивания). Единственный способ продлить срок его службы — изменить его на const sometype & a = foo();
Или назначьте его для ссылки rvalue.
Это какой-то тип && b = foo (); на самом деле значение ссылки?
да (читайте здесь для получения дополнительной информации: Разрешают ли ссылки rvalue висячие ссылки?)
Он «крадет» возвращаемое значение из foo () и отправляет то, что было в b, деструктору?
нет, это продлевает срок службы
Есть ли другой способ не иметь это предупреждение?
У вас есть три варианта: (1) назначить ссылку на rvalue, (2) назначить ссылку на const lvalue, (3) вернуть по значению, но реализовать семантику перемещения в вашем классе.
Вы также можете рассчитывать на то, что компилятор выполнит RVO для возвращаемого значения.