web-dev-qa-db-ja.com

アドレスで返される関数が左辺値になれないのはなぜですか?

参照を返す関数を設定できるのに、アドレスを返す関数を設定できないのはなぜですか。

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;
}
6
sk patra

まず、コードが壊れています。ローカル変数の参照またはアドレスを返すと、ガベージが返されます。絶対にしないでください。ここで私はあなたの例を実際のものを返すように書き直しました。

_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;
}
_

この例では、xByReferenceには値23が割り当てられています。xByAddressには値245が割り当てられています。もちろん、returnByAddress() = &x;は無効です。

ルールは次のとおりです。関数は右辺値を返します。これを回避する唯一の方法は、参照を返すことです。

returnByAddress()は、右辺値によってポインタを返します。ポインターを参照して、指し示されたものの左辺値を取得できます。

このルールに従って、ポインタへの参照を返すことができます。

_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;
}
_

このコードは、xPointerxのアドレスを指すように変更します。

7
Jeffery Thomas

例で試みていることは非常に危険です。

左辺値としての関数の結果は意味がありますが、関数が戻った後にオブジェクトが存在することを確認する必要があります。ここでは(一種の)意味のある例を示します。

#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;
}

出力はHallo world!、オフセット1のebufaに変更された後。

1
Wolf