簡體   English   中英

返回引用並返回值

[英]Returning a reference and returning a value

我不太確定我是否理解我們返回局部隨機變量的引用時為什么會有問題。 所以說我們有這個例子。

int *myFunc() {
  int phantom = 4;
  return &phantom;
}

那么通常的論據是,當使用該函數時,在執行代碼行int phantom = 4;后,變量phantom的內存不再可用int phantom = 4; 因此無法將其返回(至少到目前為止,這是我所了解的)。 另一方面,對於功能,

int myFunc() {
  int phantom = 4;
  return phantom;
}

整數變量phantom的值將返回。 (我將值的返回視為對變量phantom的基礎指針的取消引用)。

我在這里想念什么? 為什么在第一種情況下出現編譯錯誤,而在第二種情況下一切正常?

第一個不返回引用,而是返回一個指針。 指向局部變量的指針,一旦函數結束,該變量將超出范圍,從而給您留下一個不再存在的變量的流浪指針。 這就是為什么您會收到編譯器警告 (通常不是實際錯誤)的原因。

第二個代碼復制該值。 一旦return語句完成,函數內的局部變量將不再需要引用或使用。

你不會錯過太多。 只有在第一種情況下,才不會出現編譯器錯誤。

在執行代碼行int phantom = 4之后,變量phantom的內存不再可用。 所以不能退貨

不可以,它可以返回,編譯器可以為此發出警告,但不會出現錯誤。 但是,你不應該!

順便說一句,內存是可用的,但是在函數返回之后(不是在int phantom = 4;行之后)訪問它是未定義的行為。

在第二種情況下:

我看到值的返回是變量幻影的基礎指針的取消引用

您在這里覺得太復雜了。 從函數返回值可以通過使用指針來實現,但這就是實現細節。 您唯一需要關心的是返回的 因此在第二種情況下沒有問題。

第一種情況

int* myFunc()
{
   int phantom = 4;
   return &phantom;  // you are returning the address of phantom
}                    // but phantom will not "exist" outside of myfunc

不起作用,因為變量phantom是局部變量,並且僅在執行myfunc期間存在。 在那之后,它消失了。

您將返回一個變量的地址,該地址實際上將不再“存在”。

規則:永遠不要返回指針或對局部變量的引用。

還行吧:

 int myFunc()
 {
    int phantom = 4;
    return phantom;  // you are returning by value;
                     // it doesn't matter where phantom "lives"
 }                  

 int main()
 {
    int x = myFunc(); // the value returned by myFunc will be copied to x
 }

我不太確定我是否理解我們返回局部隨機變量的引用時為什么會出現問題

因為C ++標准說如果使用這樣的函數,它是未定義的行為 ,並且您希望避免程序中出現未定義的行為。 您的程序要執行的操作應由C ++語言的規則決定,而不是隨機的。

請注意,您返回的是指針而不是引用。 但這兩種情況都是未定義的行為。

那么通常的論據是,當使用該函數時,在執行代碼行int phantom = 4;后,變量phantom的內存不再可用int phantom = 4; 因此無法將其返回(至少到目前為止,這是我所了解的)。

這是以實現為中心的觀點,可以幫助您理解問題。

盡管如此,區分程序的可觀察行為與編譯器產生該行為的內部技巧之間的區別很重要。 您甚至都不知道某個變量是否占用了任何內存。 考慮“假設”規則和編譯器優化,即使已定義了行為,也可能已刪除了整個功能。 那只是幕后真正發生的事情的一個例子。

但同樣,它仍然是未定義的行為,因此任何事情都可能發生。

問題是,當您返回這樣的指針然后嘗試訪問指針時,為什么C ++標准沒有為這種情況定義行為? 答案是沒有意義的。 函數返回時,由局部變量phantom命名的對象將終止其壽命。 因此,您將擁有一個不再存在的指針,但它仍然是一個int* ,並且取消引用非nullptr int*應該會產生一個int 這是一個矛盾 ,而C ++標准只是不願意解決這種無意義的情況。

請注意,此觀察結果如何基於C ++語言規則, 而不是基於編譯器實現問題。

為什么在第一種情況下出現編譯錯誤,而在第二種情況下一切正常?

這當然是警告,而不是錯誤 ,除非您的編譯器選項使每個警告都變成錯誤。 編譯器不得拒絕代碼,因為它的格式不正確

盡管如此,您的編譯器還是會在第一種情況下提供幫助,因為它希望阻止您創建行為未定義的程序。

在第二種情況下,行為不是未定義的。 按值返回意味着您要返回的對象是一個副本 該副本是在銷毀原始副本之前完成的,然后呼叫者會收到該副本。 這不是沒有意義,也不是任何矛盾,因此它是安全且明確的行為。

在第一種情況下,通過價值回歸不幫你,因為雖然指針本身安全的復制,它的內容是什么最終導致不確定的行為。

嘗試返回指針並將其取消引用以獲取該值。

#include <iostream>

using namespace std;


int *myFunc()
{

    int number = 4;
    int *phantom = &number;

    return phantom;

}

int main()
{
    cout << myFunc() << endl; //0x....
    cout << *myFunc() << endl; //4
    return 0;
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM