一、簡介
boost::optional是boost庫中的一個模板類,它是一個封裝了一個可選對象(option value)的類。可選對象是一種可能存在,也可能不存在的值。
在實際編程中,我們常常會遇到需要對變量判定是否有值,如果有值才進行下一步操作的情況,這時候,我們常常會選擇使用指針類型並檢查是否為NULL或者採用某個特定值來表示缺少值的情況。這種處理方式相對非常繁瑣,代碼中充斥了大量的if-else語句,代碼可讀性大打折扣。而boost::optional則可以很方便地解決這個問題。
#include <boost/optional.hpp>
#include <iostream>
using namespace std;
using boost::optional;
int main()
{
optional<int> i;
cout << boolalpha << i.is_initialized() << endl; //輸出false
i = 5;
if(i)
{
cout << *i << endl; //輸出5
}
else
{
cout << "no value" << endl;
}
cout << i.value_or(0) << endl; //輸出5,如果i沒有值,則輸出0
return 0;
}
二、優點
相比於使用指針或者某個特殊的值來表示缺少值的方法,使用boost::optional有以下優點:
1. 自然易讀
和用指針或者特殊值的方式相比,boost::optional的語義更加清晰明了,代碼更容易閱讀和理解。這是因為我們可以直接使用”.”和”->”訪問optional對象內部的值,而不必在代碼中添加大量的if-else分支來判斷對象的存在狀態。
//使用指針
int *p;
if(p == NULL)
{
cout << "no value" << endl;
}
else
{
cout << *p << endl;
}
//使用特殊值
int value = -1;
if(value == -1)
{
cout << "no value" << endl;
}
else
{
cout << value << endl;
}
//boost::optional
optional<int> i;
if(i)
{
cout << *i << endl;
}
else
{
cout << "no value" << endl;
}
2. 更加安全
和使用指針的方式相比,boost::optional更加安全。當我們使用指針訪問一個已經被釋放的對象時,程序會發生內存錯誤。而如果我們使用boost::optional,只有當確實存在值的時候才會去訪問其中的對象,這樣就不會出現訪問已經被釋放的對象的情況。
//使用指針
int *p = new int(5);
delete p;
cout << *p << endl; //程序會崩潰
//boost::optional
optional<int> i(5);
i.reset();
cout << *i << endl; //不會訪問,程序不會崩潰
三、API介紹
1. 構造函數
初始化boost::optional對象,一般有以下幾種方式:
1. 使用默認構造函數
optional<int> i; //i沒有值
2. 使用值(T類型的實例化對象)初始化
optional<int> i(5); //i有一個值為5
3. 使用boost::none初始化
optional<int> i(boost::none); //i沒有值
2. 拷貝構造函數
boost::optional對象支持拷貝構造和拷貝賦值,具體實現和普通類型的對象一樣。
optional<int> i(5);
optional<int> j(i); //j也有一個值為5
3. 重載運算符
boost::optional支持以下重載運算符:
1. bool類型重載:
可以通過使用bool()來判斷是否有值。如果有值,則返回true,否則返回false。
optional<int> i;
if(i)
{
//i有值
}
else
{
//i沒有值
}
if(bool(i))
{
//i有值
}
else
{
//i沒有值
}
2. 相等(==)和不相等(!=)運算符重載:
可以將boost::optional對象與T類型(對象或值)進行比較。如果optional對象有值,且該值與T對象相等,則返回true;否則返回false。
optional<int> i(5);
int j = 5;
if(i == j)
{
//i和j的值相等
}
else
{
//i和j的值不相等
}
int k = 6;
if(i != k)
{
//i和k的值不相等
}
else
{
//i和k的值相等
}
3. 指針重載:
我們可以使用”->”來訪問optional對象的值。如果optional對象沒有值,則會拋出一個boost::bad_optional_access異常。
optional<string> p("hello world");
cout << p->size() << endl;
optional<string> q;
cout << q->size() << endl; //會拋出異常
4. 解引用(*)運算符重載:
可以使用”*”來訪問optional對象內部存儲的值。如果optional對象沒有值,則會拋出一個boost::bad_optional_access異常。
optional<string> p("hello world");
cout << *p << endl;
optional<string> q;
cout << *q << endl; //會拋出異常
4. 函數成員
boost::optional提供了一系列函數成員來方便我們使用可選對象:
1. is_initialized():
用於檢查對象是否被初始化,如果已經被初始化,則返回true,否則返回false。
optional<int> i;
cout << boolalpha << i.is_initialized() << endl; //false
i = 5;
cout << boolalpha << i.is_initialized() << endl; //true
2. reset():
用於清除對象的值(不同於將它賦值為一個沒有值的optional對象)
optional<int> i(5);
i.reset(); //現在i沒有值
3. value():
用於訪問optional對象的值。如果對象不包含值,則會拋出一個boost::bad_optional_access異常。
optional<int> i(5);
cout << i.value() << endl; //輸出5
optional<int> j;
cout << j.value() << endl; //會拋出異常
4. value_or():
用於返回optional對象的值,如果對象沒有值,則返回一個默認值。
optional<int> i;
cout << i.value_or(0) << endl; //輸出0,因為i沒有值
i = 5;
cout << i.value_or(0) << endl; //輸出5
四、使用技巧
1. 使用optional作為函數返回類型:
我們可以使用boost::optional作為函數的返回類型,這樣就可以方便地處理函數返回值可能為空的情況。如果函數的調用方需要獲取函數返回值,則可以使用optional對象的value()函數訪問其內部存儲的值。如果函數沒有返回有效值,則可通過拋出異常的方式來通知調用方。如下面所示:
optional<int> getInt()
{
int a = 5;
bool exist = false; //假設a不一定有值
if(exist)
{
return a;
}
else
{
return boost::none;
}
}
int main()
{
optional<int> i = getInt();
if(i)
{
cout << i.value() << endl;
}
else
{
cout << "no value" << endl;
}
return 0;
}
2. 使用lambda表達式:
使用lambda表達式可以方便地處理optional對象的值。lambda表達式可以將我們的邏輯代碼和optional對象的判斷分支合併在一起,讓代碼更加簡潔易讀。如下面所示:
optional<int> i(5);
optional<int> j;
auto f = [](optional<int> a, optional<int> b)
{
if(!a && !b)
{
cout << "no value" << endl;
}
else if(a && !b)
{
cout << *a << endl;
}
else if(!a && b)
{
cout << *b << endl;
}
else
{
cout << *a + *b << endl;
}
};
f(i, j); //輸出5
f(j, i); //輸出5
f(i, optional<int>()); //輸出5
f(optional<int>(), j); //輸出no value
f(i, optional<int>(10)); //輸出15
總結
boost::optional提供了一種簡單、直觀的方法來處理可選對象。與使用指針或者某個特殊值的方式相比,boost::optional具有更好的代碼可讀性和安全性。此外,使用boost::optional還可以帶來一些比較方便的使用技巧。
原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-hant/n/297888.html