亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

空引用可能嗎?

空引用可能嗎?

C++
繁星coding 2019-11-28 10:36:04
這段代碼是否有效(和定義的行為)?int &nullReference = *(int*)0;這兩個g ++以及鐺++編譯它沒有任何警告,即使使用-Wall,-Wextra,-std=c++98,-pedantic,-Weffc++...當然,該引用實際上并不為空,因為無法訪問該引用(這意味著取消引用一個空指針),但是我們可以通過檢查其地址來檢查其是否為空:if( & nullReference == 0 ) // null reference
查看完整描述

3 回答

?
長風秋雁

TA貢獻1757條經驗 獲得超7個贊

答案取決于您的觀點:


如果按照C ++標準進行判斷,則無法獲得空引用,因為您首先會獲得未定義的行為。在第一次發生未定義行為之后,該標準允許發生任何事情。因此,如果您編寫*(int*)0,那么從語言標準的角度來看,您已經具有未定義的行為,即取消引用空指針。程序的其余部分無關緊要,一旦執行了此表達式,您就退出了游戲。


但是,實際上,可以很容易地從空指針創建空引用,直到您真正嘗試訪問空引用后面的值時,您才會注意到。您的示例可能有點太簡單了,因為任何好的優化編譯器都會看到未定義的行為,并簡單地優化掉所有依賴于它的內容(甚至不會創建null引用,它也會被優化掉)。


但是,優化工作取決于編譯器來證明未定義的行為,這可能是不可能做到的??紤]一下文件內的這個簡單函數converter.cpp:


int& toReference(int* pointer) {

    return *pointer;

}

當編譯器看到此函數時,它不知道指針是否為空指針。因此,它只是生成將任何指針轉換為相應引用的代碼。(順便說一句,這是一個小問題,因為指針和引用在匯編程序中是完全相同的野獸。)現在,如果您還有另一個user.cpp包含代碼的文件


#include "converter.h"


void foo() {

    int& nullRef = toReference(nullptr);

    cout << nullRef;    //crash happens here

}

編譯器不知道toReference()將取消對傳遞的指針的引用,并假定它返回有效的引用,實際上,該引用將為空引用。調用成功,但是當您嘗試使用引用時,程序崩潰。希望。該標準允許發生任何事情,包括出現粉紅色大象。


您可能會問為什么這是相關的,畢竟,內部已經觸發了未定義的行為toReference()。答案是調試:空引用可能像空指針一樣傳播和擴散。如果您不知道可以存在空引用,并學會避免創建空引用,則可能要花費大量時間來弄清楚為什么僅在嘗試讀取普通舊int成員時成員函數似乎崩潰了(答案:實例在該成員的調用中是一個空引用,this一個空指針也是如此,并且您的成員被計算為位于地址8)。


那么如何檢查空引用呢?你給了電話


if( & nullReference == 0 ) // null reference

在你的問題。嗯,那是行不通的:按照標準,如果取消引用空指針,您將具有未定義的行為,并且不創建空引用就無法創建空引用,因此,空引用僅存在于未定義行為的領域內。由于編譯器可能會假設您未觸發未定義的行為,因此它可以假設不存在空引用(即使它很容易發出生成空引用的代碼?。_@樣,它看到了if()條件,得出結論說它不可能成立,而只是丟棄了整個if()語句。隨著鏈接時間優化的引入,以魯棒的方式檢查空引用已變得毫無可能。


TL; DR:

空引用有些可怕地存在:


它們的存在似乎是不可能的(按標準而言),

但是它們卻存在(按生成的機器代碼來確定),

但是您看不到它們是否存在(=您的嘗試將被優化),

但無論如何它們可能會殺死您(=您的程序在怪異的點崩潰,甚至更糟)。

您唯一的希望是它們不存在(=編寫您的程序以不創建它們)。


我希望那不會困擾您!


查看完整回答
反對 回復 2019-11-28
?
鳳凰求蠱

TA貢獻1825條經驗 獲得超4個贊

如果您打算找到一種在單例對象枚舉中表示空值的方法,那么(取消)引用空值(C ++ 11,nullptr)是一個壞主意。


為什么不按如下所示在類中聲明表示NULL的靜態單例對象,并添加一個返回nullptr的強制轉換指針運算符?


編輯:更正了幾種錯誤類型,并在main()中添加了if語句,以測試實際工作的強制轉換指針操作符(我忘了..我的錯)-2015年3月10日-


// Error.h

class Error {

public:

  static Error& NOT_FOUND;

  static Error& UNKNOWN;

  static Error& NONE; // singleton object that represents null


public:

  static vector<shared_ptr<Error>> _instances;

  static Error& NewInstance(const string& name, bool isNull = false);


private:

  bool _isNull;

  Error(const string& name, bool isNull = false) : _name(name), _isNull(isNull) {};

  Error() {};

  Error(const Error& src) {};

  Error& operator=(const Error& src) {};


public:

  operator Error*() { return _isNull ? nullptr : this; }

};


// Error.cpp

vector<shared_ptr<Error>> Error::_instances;

Error& Error::NewInstance(const string& name, bool isNull = false)

{

  shared_ptr<Error> pNewInst(new Error(name, isNull)).

  Error::_instances.push_back(pNewInst);

  return *pNewInst.get();

}


Error& Error::NOT_FOUND = Error::NewInstance("NOT_FOUND");

//Error& Error::NOT_FOUND = Error::NewInstance("UNKNOWN"); Edit: fixed

//Error& Error::NOT_FOUND = Error::NewInstance("NONE", true); Edit: fixed

Error& Error::UNKNOWN = Error::NewInstance("UNKNOWN");

Error& Error::NONE = Error::NewInstance("NONE");


// Main.cpp

#include "Error.h"


Error& getError() {

  return Error::UNKNOWN;

}


// Edit: To see the overload of "Error*()" in Error.h actually working

Error& getErrorNone() {

  return Error::NONE;

}


int main(void) {

  if(getError() != Error::NONE) {

    return EXIT_FAILURE;

  }


  // Edit: To see the overload of "Error*()" in Error.h actually working

  if(getErrorNone() != nullptr) {

    return EXIT_FAILURE;

  }

}


查看完整回答
反對 回復 2019-11-28
  • 3 回答
  • 0 關注
  • 860 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號