参照を返す関数を設定できるのに、アドレスを返す関数を設定できないのはなぜですか。
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;
}
まず、コードが壊れています。ローカル変数の参照またはアドレスを返すと、ガベージが返されます。絶対にしないでください。ここで私はあなたの例を実際のものを返すように書き直しました。
_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;
}
_
このコードは、xPointer
をx
のアドレスを指すように変更します。
例で試みていることは非常に危険です。
左辺値としての関数の結果は意味がありますが、関数が戻った後にオブジェクトが存在することを確認する必要があります。ここでは(一種の)意味のある例を示します。
#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のe
のbuf
がa
に変更された後。