std::optional 與 nullptr
今天在跟小 Y 聊 optional
std::optional 是一個 C++ 17 的 class,它用來表示一個值可能是空的,可以看 cppreference 我就不重複介紹了。我們也可以用一個 pointer 來做到同樣的效果,讓 nullptr 代表值是空的。
普遍認為 optional 能夠增加程式碼的可讀性,更明確的表示一個值可能是空的。當我們看到一個 pointer 的時候,我們不一定會確定那個值是空的,甚至會忽略的 null check,產生 segmentation fault。使用 optional 可以明確的表示這個值一定有可能是空的,也有 clang-tidy 工具的規則 可以防止你沒有處理值為空的 case。
對於可讀性我還有想到一個例子,比如說 std::map
的 [] 運算子。雖然我們可能早就對他的行為瞭若指掌,但想像我們第一次看到他的界面 T& operator[]( const Key& key );
你能夠想像它如果存取到一個不存在的 key 會有什麼行為嗎?想像如果他的界面是 std::optional<T> operator[]( const Key& key );
,是不是稍微就可以想像得到找不到的時候會發生什麼事情。誰會通靈的到如果不存在,它會幫你 default construct 一個出來呢?(我不是想要說他的不好,他有可能有很好的理由,我只是想純粹討論可讀性的部份)
回到 optional 與 nullptr,除了比較多人提到的可讀性之外,我覺得 optional 也對於程式碼維護性有貢獻。optional 可以透過工具,強迫你在拆開 optional 的時候,檢查的的存在性。如果今天某個地方錯誤的產生了空的值,它會馬上被發現。如果使用 nullptr,疏忽了 null check,這個 nullptr 可能會不停的傳遞。可能輾轉經過很多個 function call,終於在使用它的時候發現了問題。這個時候要再回去追錯誤的源頭,就會變得相對困難。
我認為用 nullptr 如果檢查得當,並且可以分清楚哪些指標可能為空,或許問題都不大。問題是作為一個界面設計的人,我想目標是盡量讓所有人使用這個界面的 effort 最小化,希望即便是不熟悉程式碼的使用者,也可以透過編譯器或是自動化工具,有最好的開發體驗。一個函式庫可能是無暇的,但使用者可能在使用時製造出許多問題,使用 optional 來強迫使用者 handle edge case,可以幫助使用者減少一些使用上的問題。不是函式庫開發者的我,我想很多時候,我就是我自己程式碼的使用者,好好的設計界面,其實是在幫自己減少思考的負擔XD