Por que uma função retornando por endereço não pode ser um lvalue?

5

Por que não é possível definir uma função retornando um endereço enquanto é possível definir uma função que retorna uma referência.

int* returnByAddress()
{
    int x = 20;
    return &x;
}

int& returnByReference()
{
    int x = 30;
    return x;
}

int main()
{
    returnByReference() = 23; // possible
    int x = 23;
    returnByAddress() = &x;   // not a lvalue error 
    *returnByAddress() = 245; // possible

    return 0;
}
    
por sk patra 20.01.2014 / 10:36
fonte

2 respostas

6

Para começar, seu código está quebrado. Retornar uma referência ou o endereço de uma variável local está retornando lixo. Nunca faça isso. Aqui eu reescrevi seu exemplo para retornar algo real.

int xByAddress = 20;
int xByReference = 30;

int* returnByAddress()
{
    return &xByAddress;
}

int& returnByReference()
{
    return xByReference;
}

int main()
{
    returnByReference() = 23; //possible
    int x = 23;
    returnByAddress() = &x; //not a lvalue error 
    *returnByAddress() = 245; //possible

    return 0;
}

Neste exemplo, xByReference recebe o valor 23. xByAddress recebe o valor 245. Naturalmente, returnByAddress() = &x; é inválido.

A regra é: funções retornam rvalues. A única maneira de contornar isso é retornar uma referência.

returnByAddress() retorna um ponteiro por rvalue. Você pode deferir o ponteiro para obter um lvalue da coisa apontada.

Seguindo esta regra, você pode retornar uma referência ao ponteiro.

int xByAddress = 20;
int *xPointer = nullptr;

int*& returnByPointerReference()
{
    xPointer = &xByAddress;
    return xPointer;
}

int main()
{
    int x = 23;
    returnByPointerReference() = &x; //not a lvalue error     
    return 0;
}

Este código muda xPointer para apontar para o endereço de x .

    
por 26.04.2014 / 17:45
fonte
1

O que você está tentando nos seus exemplos é muito perigoso.

Os resultados da função como lvalues podem fazer sentido, mas você deve garantir que os objetos existam depois que a função retornar. Aqui um exemplo que faz (tipo de) sentido:

#include <iostream>

/// get a R/W reference to a byte in a buffer
/// Warning: no range checking is performed
unsigned char& refByteOfBuffer(void* buf, const int offset)
{
    return reinterpret_cast<unsigned char*>(buf)[offset];
}

void testRefWrite()
{
    unsigned char buf[] = "Hello world!";
    refByteOfBuffer(buf, 1) = 'a';
    std::cout << buf << std::endl;
}

A saída será Hallo world! , depois que o e in buf no deslocamento 1 foi alterado para a .

    
por 25.02.2014 / 14:55
fonte