Что представляет собой адрес ссылки lvalue на prvalue?

Когда параметр функции имеет тип 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 Можно его адрес взят, что мне любопытно.

4

Решение

Короче говоря, потому что срок службы prvalue был продлен. Если время его жизни увеличено — по любой ссылке — это lvalue, и, следовательно, можно получить его адрес.


что представляет собой адрес? Что там живет?

Адрес представляет объект, объект, на который ссылается lref,

Prvalue недолгим, он не живет долго. Фактически, он будет уничтожен, когда оператор, создающий его, закончится.

Но когда вы создаете ссылку на prvalue (либо ссылку на rvalue, либо ссылку на const lvalue), время ее жизни увеличивается. Ref .::

Rvalue может быть использован для инициализации const lvalue [Rvalue] ссылка, в этом случае время жизни объекта, идентифицируемого Rvalue является продлен до конца области ссылки.

Теперь имеет смысл взять его адрес, так как это значение для всех намерений и целей. Теперь, когда prvalue имеет неопределенное время жизни, это lvalue.

Однако брать адрес prvalue не имеет смысла, и, вероятно, поэтому он запрещен:

  • Значение уничтожается после следующих операторов, так что вы ничего не можете сделать с адресом, кроме, может быть, распечатать его.
  • Если вы берете адрес чего-либо, компилятор должен фактически создать объект. Иногда компилятор оптимизирует тривиальные переменные, но если вы взяли их адрес, компилятору не будет разрешено их оптимизировать.

    Таким образом, получение адреса prvalue приведет к тому, что компилятор не сможет полностью исключить значение без каких-либо преимуществ (см. Пункт 1).

4

Другие решения

Внутри функции 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 (у него есть имя), так что вы можете взять его адрес и он изменчив.

5

На простом английском:

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 тоже.

3
По вопросам рекламы [email protected]