Когда параметр функции имеет тип lvalue ссылка lref
:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
а также lref
связан с prvalue:
PrintAddress(lref.substr() /* temporary of type std::string */)
что представляет собой адрес? Что там живет?
Prvalue не может иметь свой адрес. Но ссылка lvalue в prvalue Можно его адрес взят, что мне любопытно.
Короче говоря, потому что срок службы prvalue был продлен. Если время его жизни увеличено — по любой ссылке — это lvalue, и, следовательно, можно получить его адрес.
что представляет собой адрес? Что там живет?
Адрес представляет объект, объект, на который ссылается lref
,
Prvalue недолгим, он не живет долго. Фактически, он будет уничтожен, когда оператор, создающий его, закончится.
Но когда вы создаете ссылку на prvalue (либо ссылку на rvalue, либо ссылку на const lvalue), время ее жизни увеличивается. Ref .::
Rvalue может быть использован для инициализации const lvalue [Rvalue] ссылка, в этом случае время жизни объекта, идентифицируемого Rvalue является продлен до конца области ссылки.
Теперь имеет смысл взять его адрес, так как это значение для всех намерений и целей. Теперь, когда prvalue имеет неопределенное время жизни, это lvalue.
Однако брать адрес prvalue не имеет смысла, и, вероятно, поэтому он запрещен:
Если вы берете адрес чего-либо, компилятор должен фактически создать объект. Иногда компилятор оптимизирует тривиальные переменные, но если вы взяли их адрес, компилятору не будет разрешено их оптимизировать.
Таким образом, получение адреса prvalue приведет к тому, что компилятор не сможет полностью исключить значение без каких-либо преимуществ (см. Пункт 1).
Внутри функции lref
это не prvalue, это lvalue, и вы можете взять его адрес.
Существует распространенное заблуждение о rvalues против lvalues.
Именованный параметр всегда является lvalue. Независимо от того, является ли это ссылочным типом, связанным с rvalue. Через const &
ссылочный тип, вы даже не можете сказать, какую категорию значений имеет объект на самом деле в точке, где вызывается функция. Ссылки Rvalue и неконстантные ссылки Lvalue дают вам эту информацию:
void foo(std::string& L, std::string&& R)
{
// yeah i know L is already an lvalue at the point where foo is called
// R on the other hand is an rvalue at the point where we get called
// so we can 'safely' move from it or something...
}
Временная строка является prvalue в контексте вызывающей стороны (в точке PrintAddress
называется). В контексте вызываемого абонента (в PrintAddress
) lref
является ссылкой на lvalue, потому что в этом контексте это фактически lvalue.
PrintAddress
не знает об ограниченном времени жизни переданного аргумента и от PrintAddress
С точки зрения объекта «всегда» там.
std::string q("abcd");
PrintAddress(q.substr(1)); // print address of temporary
концептуально эквивалентно:
std::string q("abcd");
{
const std::string& lref = q.substr(1);
std::cout << &lref << std::endl;
}
где временный испытывает продление его жизни до конца области, в которой lref
определяется (что до конца PrintAddress
область действия функции в настоящем примере).
что представляет собой адрес? Что там живет?
std::string
объект, содержащий переданный контент.
И является ли законным (в C ++ и в отношении памяти) запись по этому адресу?
Нет, было бы законно, если бы вы использовали ссылку rvalue:
void PrintAddressR(std::string&& rref) {
rref += "Hello"; // writing possible
std::cout << &rref << std::endl; // taking the address possible
}
// ...
PrintAddressR(q.substr(1)); // yep, can do that...
То же самое относится и здесь: rref
это lvalue (у него есть имя), так что вы можете взять его адрес и он изменчив.
На простом английском:
void PrintAddress(const std::string& lref) {
std::cout << &lref << std::endl;
}
Любой объект, имеющий имя, является lvalue
следовательно, любое использование lref
в рамках вышеуказанной функции lvalue
использовать.
Когда вы вызвали функцию с помощью:
PrintAddress(lref.substr() /* temporary of type std::string */)
Конечно, lref.substr()
производит временный, который является rvalue
, но rvalues
может связываться с (время его продления увеличивается) ссылками const lvalue или ссылками rvalue.
Даже если вы предоставили rvalue
перегрузки, за то, что у него есть имя, это «ценность чего-то» в рамках своей области, пример:
#include <string>
#include <iostream>
void PrintAddress(const std::string& lref) {
std::cout << "LValue: " << &lref << std::endl;
}
void PrintAddress(std::string&& `rref`) {
std::cout << "RValue: " << &rref << std::endl; //You can take address of `rref`
}
int main(){
std::string str = "Hahaha";
PrintAddress(str);
PrintAddress(str.substr(2));
}
Просто помни:
В C ++ любой объект (будь то тип ценности, тип ссылки или же тип указателя) который имеет название является именующий
Также знаю, что некоторые выражения производить lvalues тоже.