C++ std::optional 用法與範例

本篇 ShengYu 介紹 C++ std::optional 用法與範例,std::optional 是 C++17 中引入的一個 template 樣板類別,它代表一個可能存在也可能不存在的值,也就是有值或沒有值。你可以將它視為一個安全的容器,用於存儲可能為空的值。std::optional 它的主要用途是解決傳統的指標和參考可能為空的問題,從而增強了程式碼的安全性和可讀性。

具體來說,std::optional 允許你在一個容器中儲存值,同時可以指示該值是否存在。這對於那些可能回傳空值的函式或者需要可選參數的函式來說非常有用。以下是 std::optional 的一些基本用法。

要使用 std::optional 的話,需要引入的標頭檔: <optional>

C++ 建立 std::optional

這邊介紹 C++ 建立一個空的 std::optional,在建立 std::optional 時,你可以指定它的類型,也可以讓編譯器推導出類型。如果你沒有給出初始值,則建立出來的 std::optional 將是空的。

1
2
std::optional<int> opt;
std::optional<string> opt2;

將值放入 std::optional,將值放入 std::optional 中,這樣它就不再是空的。

1
2
std::optional<int> opt = 123;
std::optional<string> opt2 = "hello";

檢查 std::optional 是否有值

C++ 在使用 std::optional 中的值之前,你可能需要檢查它是否存在,以避免未定義行為。以下是個簡單的檢查 std::optional 是否有值的範例,

std-optional.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// g++ std-optional.cpp -o a.out -std=c++17
#include <iostream>
#include <string>
#include <optional>

using namespace std;

int main() {
std::optional<int> opt = 123;
if (opt.has_value()) {
cout << "opt has value" << endl;
// 執行當前存在值的程式碼...
} else {
cout << "opt no value" << endl;
// 執行當前不存在值的程式碼...
}

std::optional<std::string> opt2;
if (opt2.has_value()) {
cout << "opt2 has value" << endl;
} else {
cout << "opt2 no value" << endl;
}
return 0;
}

結果輸出如下,

1
2
opt has value
opt2 no value

獲取 std::optional 中的值

在 C++ 中你可以使用 value() 方法從 std::optional 中獲取值,但要小心,如果 std::optional 是空的,這可能會拋出異常。另一個選擇是使用 value_or() 方法,它在 std::optional 為空時回傳預設值。

1
2
3
4
int value = opt.value(); // 如果沒有值,這可能會拋出異常
// 或者
int value = opt.value_or(default_value); // 如果沒有值,回傳預設值
int value = opt.value_or(0); // 如果沒有值,回傳預設值 0

重設 std::optional 中的值

你可以使用 reset() 方法將 std::optional 重設為空。

std-optional2.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// g++ std-optional2.cpp -o a.out -std=c++17
#include <iostream>
#include <optional>

using namespace std;

int main() {
std::optional<int> opt = 123;
if (opt.has_value()) {
cout << "opt has value" << endl;
} else {
cout << "opt no value" << endl;
}

opt.reset(); // 將 `std::optional` 重設為空

if (opt.has_value()) {
cout << "opt has value" << endl;
} else {
cout << "opt no value" << endl;
}
return 0;
}

結果輸出如下,

1
2
opt has value
opt no value

檢索 std::optional 中的值,並且同時判斷是否存在

在某些情況下,你可能需要同時檢索 std::optional 中的值並檢查它是否存在。你可以使用 auto 關鍵字以及 if 陳述式的新形式來實現這一目的。

1
2
3
4
5
6
7
8
9
10
11
std::optional<int> getValue() {
std::optional<int> num = 123;
return num;
}

std::optional<int> opt = getValue();
if (auto value = opt; value) {
// 執行當前存在值的程式碼,同時 `value` 中存有值
} else {
// 執行當前不存在值的程式碼
}

上述範例介紹 std::optional 用在函式換回傳值的範例,std::optional 的出現讓 function 回傳值多了一個選擇,有值或是 nullopt,讓人能更清楚表達程式碼用意。

以上是 std::optional 的一些基本用法,讓你可以更安全地處理可能為空的值。以下介紹 std::optional 常見使用情況。

std::optional<int> 的常見用法

以下介紹 std::optional 有設定 int 值跟沒設定 int 值的使用情況,std::optional 沒設定值或者設定成 std::nullopt 都會讓判斷式變成 false,

std-optional3.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
// g++ std-optional3.cpp -o a.out -std=c++17
#include <iostream>
#include <optional>

using namespace std;

void test_optional_int(std::optional<int> num) {
if (num) {
int n = num.value();
cout << "true, " << n << endl;
} else {
cout << "false" << endl;
}

if (num.has_value()) {
auto n = num.value();
cout << "has value, " << n << endl;
} else {
cout << "no value" << endl;
}

if (num == std::nullopt) {
cout << "nullopt" << endl;
} else {
auto n = num.value();
cout << "not nullopt, " << n << endl;
}
}

int main() {
std::optional<int> num;
test_optional_int(num);
cout << "---" << endl;
num = 123;
test_optional_int(num);
cout << "---" << endl;
num = std::nullopt;
test_optional_int(num);
return 0;
}

結果輸出如下,

1
2
3
4
5
6
7
8
9
10
11
false
no value
nullopt
---
true, 123
has value, 123
not nullopt, 123
---
false
no value
nullopt

std::optional<string> 的常見用法

以下介紹 std::optional 有設定 string 值跟沒設定 string 值的使用情況,std::optional 沒設定值或者設定成 std::nullopt 都會讓判斷式變成 false,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// g++ std-optional4.cpp -o a.out -std=c++17
#include <iostream>
#include <string>
#include <optional>

using namespace std;

void test_optional_int(std::optional<std::string> str) {
if (str) {
std::string s = str.value();
cout << "true, " << s << endl;
} else {
cout << "false" << endl;
}

if (str.has_value()) {
auto s = str.value();
cout << "has value, " << s << endl;
} else {
cout << "no value" << endl;
}

if (str == std::nullopt) {
cout << "nullopt" << endl;
} else {
auto s = str.value();
cout << "not nullopt, " << s << endl;
cout << "not nullopt, " << (*str) << endl; // 其他寫法
printf("not nullopt, %s\n", (*str).c_str()); // 其他寫法
}
}

int main() {
std::optional<std::string> str;
test_optional_int(str);
cout << "---" << endl;
str = "hello";
test_optional_int(str);
cout << "---" << endl;
str = std::nullopt;
test_optional_int(str);
return 0;
}

結果輸出如下,

1
2
3
4
5
6
7
8
9
10
11
12
13
false
no value
nullopt
---
true, hello
has value, hello
not nullopt, hello
not nullopt, hello
not nullopt, hello
---
false
no value
nullopt

使用 std::optional 後確實讓 code 看起來更清楚,更能清楚表達程式碼與原作者的意涵。

std::optional 包 struct/class 的用法

這邊介紹 std::optional 包 struct 或是 class 的用法,std::optional 也可以用 -> 來直接存取 member 或 member function,範例如下,

std-optional5.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// g++ std-optional5.cpp -o a.out -std=c++17
#include <iostream>
#include <string>
#include <optional>

using namespace std;

struct Student {
uint32_t id;
std::string name;
};

int main() {

Student student;
student.id = 100;
student.name = "Alice";
std::optional<Student> optStudent1;
std::optional<Student> optStudent2;
optStudent2 = student;

if (optStudent1) {
printf("optStudent1 id = %d\n", optStudent1->id);
printf("optStudent1 name = %s\n", optStudent1->name.c_str()); // 存取 member function
printf("optStudent1 name size = %zu\n", optStudent1->name.size()); // 存取 member function
}

if (optStudent2) {
printf("optStudent2 id = %d\n", optStudent2->id);
printf("optStudent2 name = %s\n", optStudent2->name.c_str()); // 存取 member function
printf("optStudent2 name size = %zu\n", optStudent2->name.size()); // 存取 member function
}

return 0;
}

結果輸出如下,

1
2
3
optStudent2 id = 100
optStudent2 name = Alice
optStudent2 name size = 5

C++ std::optional 的主要用途

以下是一些 std::optional 的主要用途:

  1. 代替可能為空的指標或參考:通常情況下,我們可能會用指標或參考來表示一個可能為空的值。但是指標可能為空,並且需要額外的解參考操作來獲取實際的值,這會增加程式碼的覆雜度和潛在的錯誤。使用 std::optional 可以更加直觀地表達這種情況。
  2. 函式回傳值可能為空:有些函式可能無法始終返回有效的結果,而是可能返回空。使用 std::optional 可以清晰地表示函式的回傳值可能為空,並且無需使用特殊的回傳值表示空。
  3. 避免使用異常處理空值:在早期有時會使用異常來表示一個函式無法返回有效結果的情況。但是異常處理可能會帶來額外的開銷,並且可能使程式碼更難以理解。std::optional 提供了一種更加顯式的方式來處理可能為空的值,而無需使用異常。
  4. 提高程式碼的可讀性和安全性:通過使用 std::optional,程式碼的意圖更加明確,可以減少錯誤的發生,並且使程式碼更容易理解和維護。

總之,std::optional 是 C++ 中一種非常有用的工具,可以有效地處理可能為空的值,提高程式碼的安全性和可讀性。

以上就是 C++ std::optional 用法與範例介紹,
如果你覺得我的文章寫得不錯、對你有幫助的話記得 Facebook 按讚支持一下!

其它相關文章推薦
C/C++ 新手入門教學懶人包
std::string 用法與範例
std::vector 用法與範例
std::sort 用法與範例
std::map 用法與範例
std::set 用法與範例