[C++] std::optional์ ๋ชจ๋ ๊ฒ
std::optional์ ๋ํ ์์ธํ ์ค๋ช
๊ณผ ์ค๋ฌด ์์
std::optional์ C++17์์ ๋์ ๋ ๋งค์ฐ ์ ์ฉํ ๊ธฐ๋ฅ์ผ๋ก, ๊ฐ์ด "์์ ์๋ ์๊ณ ์์ ์๋ ์๋" ์ํฉ์ ์์ ํ๊ณ ๋ช ์์ ์ผ๋ก ํํํ ์ ์์ต๋๋ค. ์ด๋ ์ด์ ์ nullptr, NULL, ํน์ ํน๋ณํ ๊ฐ(์: -1)์ ์ฌ์ฉํ์ฌ "๊ฐ ์์"์ ํํํ๋ ๋ฐฉ์๋ณด๋ค ํจ์ฌ ๋ ์์ ํ๊ณ ๋ช ํํ ์ฝ๋๋ฅผ ์์ฑํ ์ ์๊ฒ ํด์ค๋๋ค.
1. std::optional์ ๊ธฐ๋ณธ ๊ฐ๋
std::optional์ ํ ํ๋ฆฟ ํด๋์ค์ด๋ฉฐ, ์ด๋ค ํ์ T์ ๋ํด std::optional<T>๋ก ์ฌ์ฉ๋ฉ๋๋ค. ์ด ํ์ ์ T ํ์ ์ ๊ฐ์ ๊ฐ์ง ์๋ ์๊ณ , ๊ฐ์ด ์์์ ๋ํ๋ด๋ std::nullopt ์ํ์ผ ์๋ ์์ต๋๋ค.
- ์ ์ธ ๋ฐ ์ด๊ธฐํ:
std::optional<int> maybeInt;
std::optional<std::string> maybeString = "Hello";
std::optional<double> maybeDouble = std::nullopt; // ๊ฐ์ด ์์
- ๊ฐ ํ ๋น ๋ฐ ์ ๊ทผ:
maybeInt = 42;
if (maybeInt) {
std::cout << "Value: " << *maybeInt << std::endl; // Dereferencing the optional
} else {
std::cout << "No value" << std::endl;
}
2. ์ค๋ฌด์์์ std::optional ์ฌ์ฉ ์์
์์ 1: ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ์์ ์ฌ์ฉ
๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ์์ ํน์ ํค์ ํด๋นํ๋ ๊ฐ์ ์ฐพ์ง ๋ชปํ ์ ์๋ ์ํฉ์์ std::optional์ ์ฌ์ฉํ์ฌ ์กฐํ ๊ฒฐ๊ณผ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
#include <iostream>
#include <optional>
#include <unordered_map>
#include <string>
class Database {
public:
std::optional<std::string> getUserById(int id) {
if (auto it = users.find(id); it != users.end()) {
return it->second;
}
return std::nullopt; // ์ฌ์ฉ์ ์์
}
void addUser(int id, const std::string& name) {
users[id] = name;
}
private:
std::unordered_map<int, std::string> users;
};
int main() {
Database db;
db.addUser(1, "Alice");
db.addUser(2, "Bob");
auto user = db.getUserById(1);
if (user) {
std::cout << "User found: " << *user << std::endl;
} else {
std::cout << "User not found" << std::endl;
}
user = db.getUserById(3);
if (user) {
std::cout << "User found: " << *user << std::endl;
} else {
std::cout << "User not found" << std::endl;
}
return 0;
}
์ค๋ช
: ์ด ์ฝ๋์์ getUserById ํจ์๋ ํน์ ์ฌ์ฉ์ ID๋ฅผ ์กฐํํ๊ณ , ์ฌ์ฉ์๊ฐ ์กด์ฌํ๋ฉด std::optional<std::string>์ ๋ฐํํ๋ฉฐ, ์กด์ฌํ์ง ์์ผ๋ฉด std::nullopt์ ๋ฐํํฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํจ์ ํธ์ถ ์ธก์์ ๋ฐํ ๊ฐ์ ์์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์์ 2: ์ค์ ํ์ผ์์ ์ต์ ๊ฐ ์ฝ๊ธฐ
์ด๋ค ํ๋ก๊ทธ๋จ์์๋ ์ค์ ํ์ผ์์ ํน์ ์ต์ ๊ฐ์ ์ฝ์ด์์ผ ํ์ง๋ง, ํด๋น ์ต์ ์ด ์กด์ฌํ์ง ์์ ์๋ ์์ต๋๋ค. ์ด๋ std::optional์ ์ฌ์ฉํ๋ฉด ์ด๋ฐ ์ํฉ์ ๊น๋ํ๊ฒ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
#include <iostream>
#include <optional>
#include <map>
#include <string>
class ConfigReader {
public:
ConfigReader(const std::map<std::string, std::string>& configMap)
: config(configMap) {}
std::optional<std::string> getValue(const std::string& key) const {
auto it = config.find(key);
if (it != config.end()) {
return it->second;
}
return std::nullopt;
}
private:
std::map<std::string, std::string> config;
};
int main() {
std::map<std::string, std::string> configMap = {
{"host", "localhost"},
{"port", "8080"}
};
ConfigReader config(configMap);
auto host = config.getValue("host");
std::cout << "Host: " << (host ? *host : "Not specified") << std::endl;
auto timeout = config.getValue("timeout");
std::cout << "Timeout: " << (timeout ? *timeout : "Not specified") << std::endl;
return 0;
}
์ค๋ช
: ์ด ์์ ์์๋ ConfigReader ํด๋์ค๊ฐ ์ค์ ํ์ผ์ ์ฝ์ด์ ํน์ ํค์ ๋ํ ๊ฐ์ ๋ฐํํฉ๋๋ค. ํค๊ฐ ์กด์ฌํ์ง ์์ผ๋ฉด std::nullopt์ ๋ฐํํ์ฌ, ํจ์ ํธ์ถ ์ธก์์ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๋ช
์์ ์ผ๋ก ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
์์ 3: ๋คํธ์ํฌ ํต์ ์์ ์๋ต ์ฒ๋ฆฌ
๋คํธ์ํฌ ํต์ ์์ ์๋ฒ์ ์๋ต์ด ์ฌ ์๋ ์๊ณ , ํ์์์์ผ๋ก ์ธํด ์๋ต์ด ์ค์ง ์์ ์๋ ์์ต๋๋ค. ์ด๋ฐ ๊ฒฝ์ฐ std::optional์ ์ฌ์ฉํ์ฌ ์๋ต์ด ์กด์ฌํ๋์ง ์ฌ๋ถ๋ฅผ ์ฒ๋ฆฌํ ์ ์์ต๋๋ค.
#include <iostream>
#include <optional>
#include <string>
#include <thread>
#include <chrono>
std::optional<std::string> fetchDataFromServer(bool simulateTimeout) {
if (simulateTimeout) {
return std::nullopt; // ํ์์์ ๋ฐ์
} else {
std::this_thread::sleep_for(std::chrono::seconds(1)); // ๋คํธ์ํฌ ์ง์ฐ ์๊ฐ ์๋ฎฌ๋ ์ด์
return "Server response data";
}
}
int main() {
auto response = fetchDataFromServer(false);
if (response) {
std::cout << "Received: " << *response << std::endl;
} else {
std::cout << "No response from server (timeout)." << std::endl;
}
response = fetchDataFromServer(true);
if (response) {
std::cout << "Received: " << *response << std::endl;
} else {
std::cout << "No response from server (timeout)." << std::endl;
}
return 0;
}
์ค๋ช
: ์๋ฒ๋ก๋ถํฐ ๋ฐ์ดํฐ๋ฅผ ๋ฐ์์ค๋ fetchDataFromServer ํจ์๋ ๋คํธ์ํฌ ํ์์์์ ์๋ฎฌ๋ ์ด์
ํ์ฌ std::optional<std::string>์ ๋ฐํํฉ๋๋ค. ํ์์์์ด ๋ฐ์ํ๋ฉด std::nullopt์ ๋ฐํํ์ฌ ์๋ต์ด ์์์ ๋ช
์์ ์ผ๋ก ๋ํ๋
๋๋ค.
3. std::optional ์ฌ์ฉ ์์ ์ฃผ์ ์ฌํญ
- ์ต์ ๋์ ํฌ๊ธฐ: std::optional์ ๋ด๋ถ์ ์ผ๋ก ๊ฐ๊ณผ ์กด์ฌ ์ฌ๋ถ๋ฅผ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์, ๊ฐ ํ์ ์ ํฌ๊ธฐ๋ณด๋ค ๋ ํฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์์ ํฌ๊ธฐ์ ํ์ ์ ๋ํด์๋ ํฌ๊ฒ ๋ฌธ์ ๋์ง ์์ง๋ง, ํฐ ๊ฐ์ฒด๋ฅผ ์ต์ ๋๋ก ๋ค๋ฃฐ ๋๋ ๋ฉ๋ชจ๋ฆฌ ์ฌ์ฉ๋์ ์ ์ํด์ผ ํฉ๋๋ค.
- ๋น ์ํ ์ ๊ทผ: std::optional์ด ๋น์ด์๋ ์ํ์์ ๊ฐ์ ์ฐธ์กฐํ๋ ค๊ณ ํ๋ฉด ๋ฐํ์ ์๋ฌ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ฐ๋ผ์ ํญ์ if (opt) ์กฐ๊ฑด๋ฌธ์ ํตํด ๊ฐ์ด ์๋์ง ํ์ธํ ํ์ ์ ๊ทผํด์ผ ํฉ๋๋ค.
- ๊ธฐ๋ณธ ์ ๊ณต ํจ์ ํ์ฉ: std::optional์ value_or, has_value, emplace ๋ฑ์ ์ ์ฉํ ๋ฉค๋ฒ ํจ์๋ฅผ ์ ๊ณตํฉ๋๋ค. ์ด๋ฅผ ํ์ฉํ์ฌ ๊ธฐ๋ณธ ๊ฐ์ ์ค์ ํ๊ฑฐ๋ ์กฐ๊ฑด์ ๋ฐ๋ผ ๊ฐ์ ์ฝ๊ฒ ์ค์ ํ ์ ์์ต๋๋ค.
std::optional<int> optInt = std::nullopt;
int value = optInt.value_or(10); // optInt๊ฐ ๋น์ด์์ผ๋ฉด 10์ ์ฌ์ฉ
std::optional์ ์ฝ๋์ ์์ ์ฑ๊ณผ ๊ฐ๋ ์ฑ์ ํฌ๊ฒ ํฅ์์ํฌ ์ ์๋ ๋๊ตฌ๋ก, ํนํ ํจ์์ ๋ฐํ ํ์ ์ผ๋ก ๋งค์ฐ ์ ์ฉํ๊ฒ ์ฌ์ฉ๋ฉ๋๋ค. ์ด๋ฅผ ํตํด "๊ฐ ์์"์ ๋ช ์์ ์ผ๋ก ํํํ๊ณ ์ฒ๋ฆฌํ๋ ์ฝ๋ ์์ฑ์ด ๊ฐ๋ฅํด์ง๋๋ค.