std::from_chars / to_chars 고성능 문자열 변환
std::from_chars와 std::to_chars는 C++17에서 도입된 저수준 고성능 문자열 변환 함수입니다. 로케일 독립적이고 동적 메모리 할당이 없으며, 예외도 던지지 않아 파서, 직렬화, 로깅 등 성능 민감한 경로에 적합합니다.
1. from_chars — 문자열 → 숫자
섹션 제목: “1. from_chars — 문자열 → 숫자”#include <charconv>#include <string_view>#include <cassert>
int main(){ std::string_view sv = "12345"; int result{};
auto [ptr, ec] = std::from_chars(sv.data(), sv.data() + sv.size(), result);
if (ec == std::errc{}) // 성공: result == 12345, ptr == sv.end() assert(result == 12345); else if (ec == std::errc::invalid_argument) // 숫자가 아닌 입력 ; else if (ec == std::errc::result_out_of_range) // 오버플로 ;}2. to_chars — 숫자 → 문자열
섹션 제목: “2. to_chars — 숫자 → 문자열”#include <charconv>#include <array>#include <string_view>
int main(){ int value = 42; std::array<char, 20> buf;
auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), value);
if (ec == std::errc{}) { std::string_view sv(buf.data(), ptr); // sv == "42" }}3. 진수 변환
섹션 제목: “3. 진수 변환”#include <charconv>#include <array>
int parse_hex(std::string_view s){ int result{}; std::from_chars(s.data(), s.data() + s.size(), result, 16); return result;}
// "ff" → 255, "1A" → 26
std::string to_hex(int v){ std::array<char, 20> buf; auto [ptr, ec] = std::to_chars(buf.data(), buf.data() + buf.size(), v, 16); return std::string(buf.data(), ptr);}// 255 → "ff"4. 부동소수점 변환 (C++17)
섹션 제목: “4. 부동소수점 변환 (C++17)”#include <charconv>#include <array>
double parse_double(std::string_view s){ double result{}; std::from_chars(s.data(), s.data() + s.size(), result); return result;}
// 부동소수점 출력 형식 제어std::string format_double(double v){ std::array<char, 32> buf; // 고정 소수점 6자리 auto [ptr, ec] = std::to_chars( buf.data(), buf.data() + buf.size(), v, std::chars_format::fixed, 6); return std::string(buf.data(), ptr);}// 3.14159265 → "3.141593"std::chars_format 옵션:
fixed— 고정 소수점scientific— 과학적 표기 (1.23e+04)hex— 16진수 부동소수점general— 더 짧은 형식 자동 선택
5. 기존 방법과 성능 비교
섹션 제목: “5. 기존 방법과 성능 비교”| 함수 | 로케일 의존 | 예외 | 동적 할당 | 상대 속도 |
|---|---|---|---|---|
atoi | ✗ | ✗ | ✗ | 기준 |
stoi | ✓ | ✓ | ✓ | 느림 |
sscanf | ✓ | ✗ | ✗ | 느림 |
from_chars | ✗ | ✗ | ✗ | 빠름 (~3×) |
6. 실전 패턴 — CSV 파서
섹션 제목: “6. 실전 패턴 — CSV 파서”#include <charconv>#include <string_view>#include <vector>
std::vector<int> parse_csv_ints(std::string_view line){ std::vector<int> result; const char* ptr = line.data(); const char* end = ptr + line.size();
while (ptr < end) { int val{}; auto [next, ec] = std::from_chars(ptr, end, val);
if (ec == std::errc{}) result.push_back(val);
ptr = next; while (ptr < end && (*ptr == ',' || *ptr == ' ')) ++ptr; // 구분자 건너뛰기 } return result;}
// "1, 2, 3, 42" → {1, 2, 3, 42}7. 유틸리티 래퍼
섹션 제목: “7. 유틸리티 래퍼”#include <charconv>#include <optional>#include <string_view>
template<typename T>std::optional<T> parse(std::string_view s) noexcept{ T result{}; auto [ptr, ec] = std::from_chars(s.data(), s.data() + s.size(), result); if (ec == std::errc{} && ptr == s.data() + s.size()) return result; return std::nullopt;}
auto v = parse<int>("123"); // optional{123}auto bad = parse<int>("12x"); // nullopt (전체 소비 안됨)from_chars/to_chars는 파서, 직렬화, 로깅처럼 많은 양의 숫자 변환이 필요한 경로에서 stoi/to_string의 로케일 오버헤드와 예외 비용을 제거합니다. std::errc로 오류를 값으로 처리하고 동적 할당이 전혀 없으므로 임베디드나 게임 서버 같은 성능 민감한 환경에서도 안전하게 사용할 수 있습니다.