본문 바로가기
개발/C++ (98,03,11,14,17,20,23)

Modern C++ : std::ostream & std::istream (98, 11, 17, 20)

by snowoods 2025. 9. 2.

Modern C++

 

std::ostream & std::istream

 

개요

std::ostreamstd::istream은 C++ 표준 라이브러리에서 제공하는 입출력 스트림 클래스로, 각각 출력과 입력을 담당합니다. 이들은 형식화된 입출력과 형식화되지 않은 입출력 모두를 지원하며, 파일, 메모리 버퍼, 표준 입출력 등 다양한 소스/대상과 연동할 수 있습니다.

 

C++ 버전별 주요 키워드 도입 시기

  • C++98: 기본 std::ostream, std::istream 클래스 도입
  • C++11: 이동 생성자/대입 연산자 추가, noexcept 지정자 추가
  • C++17: std::byte 지원 추가
  • C++20: std::format과의 통합, synchronized_ 접두사 출력 함수 추가

 

내용 설명

std::ostreamstd::istream의 주요 특징:

  1. 계층 구조: std::ios_basestd::iosstd::ostream/std::istream
  2. 스트림 상태 관리: good(), eof(), fail(), bad() 등의 상태 플래그 제공
  3. 형식 지정자: std::hex, std::setw, std::setprecision 등 다양한 조작자 제공
  4. 버퍼링: 내부 버퍼를 통해 효율적인 입출력 처리
  5. 예외 처리: exceptions() 메서드를 통한 예외 처리 지원

 

예제 코드

#include <fstream>
#include <iostream>
#include <string>

struct PlayerData
{
    std::uint32_t id;
    float x_pos;
    float y_pos;
};

void print_player_pos(const PlayerData &player)
{
    std::cout << "Pos: (" << player.x_pos << ", " << player.y_pos << ")\n";
}

int write_line_to_file(std::string_view filepath, const std::string &line)
{
    auto file = std::ofstream{};
    file.open(filepath.data(), std::ios::out);
    if (file.fail())
        return 1;

    file << line << '\n';

    if (!file.good())
        return 1;

    return 0;
}

int write_to_bin_file(std::string_view filepath, const PlayerData &data)
{
    auto file = std::ofstream{};
    file.open(filepath.data(), std::ios::out | std::ios::binary);
    if (file.fail())
        return 1;

    file.write(reinterpret_cast<const char*>(&data), sizeof(PlayerData));

    if (!file.good())
        return 1;

    return 0;
}

int read_from_bin_file(std::string_view filepath, PlayerData &data)
{
    auto file = std::ifstream{};
    file.open(filepath.data(), std::ios::in | std::ios::binary);
    if (file.fail())
        return 1;

    file.read(reinterpret_cast<char*>(&data), sizeof(PlayerData));

    if (!file.good())
        return 1;

    return 0;
}

int main()
{
    // 텍스트 파일 쓰기 예제
    const auto text = std::string{"My sample text."};
    const auto filename1 = std::string{"text.txt"};
    write_line_to_file(filename1, text);

    // 바이너리 파일 쓰기 예제
    const auto player = PlayerData{.id = 0, .x_pos = 10.0F, .y_pos = 110.0F};
    const auto filename2 = std::string{"player.bin"};
    write_to_bin_file(filename2, player);

    // 바이너리 파일 읽기 예제
    auto player2 = PlayerData{};
    read_from_bin_file(filename2, player2);
    print_player_pos(player2);

    return 0;
}

 

실행 결과

Pos: (10, 110)

 

활용팁

  1. 에러 처리: 항상 스트림 연산 후 good(), fail(), bad() 등을 사용하여 오류를 확인하세요.
  2. 리소스 관리: RAII 원칙을 따르기 위해 스마트 포인터나 스택 객체를 사용하여 파일 핸들을 관리하세요.
  3. 성능: 반복적인 입출력 작업 시 std::ios_base::sync_with_stdio(false)를 고려하세요.
  4. 이진 데이터: 이진 데이터를 다룰 때는 reinterpret_cast 대신 std::bit_cast(C++20)를 사용하는 것이 더 안전합니다.
  5. 유니코드: 유니코드 문자열을 다룰 때는 std::wstringstd::wcout을 사용하거나, C++20의 std::u8stringstd::format을 고려하세요.