データ処理モジュールの設計
コンテスト参加者データを処理するシステムをC++で実装する際の核心技術について解説する。以下に主要コンポーネントの実装例を示す。
データモデルの定義
#pragma once
#include <iomanip>
#include <string>
struct Participant {
long student_id;
std::string full_name;
std::string department;
int problem_count;
int penalty_time;
};
std::ostream& operator<<(std::ostream& os, const Participant& p) {
os << std::left
<< std::setw(12) << p.student_id
<< std::setw(18) << p.full_name
<< std::setw(20) << p.department
<< std::setw(8) << p.problem_count
<< std::setw(8) << p.penalty_time;
return os;
}
std::istream& operator>>(std::istream& is, Participant& p) {
is >> p.student_id >> p.full_name
>> p.department >> p.problem_count >> p.penalty_time;
return is;
}
ファイル操作の実装
#include <fstream>
#include <sstream>
#include <vector>
#include "participant.h"
std::vector<Participant> load_data(const std::string& path) {
std::ifstream input(path);
if (!input) throw std::runtime_error("ファイルオープン失敗: " + path);
std::string header;
std::getline(input, header);
std::vector<Participant> records;
std::string line;
int line_number = 2;
while (std::getline(input, line)) {
std::istringstream line_stream(line);
int sequence;
Participant entry;
if (line_stream >> sequence >> entry) {
records.push_back(entry);
} else {
std::cerr << "警告: 行 " << line_number
<< " のフォーマット不正、スキップします\n";
}
line_number++;
}
return records;
}
データ検証の強化手法
不正データに対する堅牢性を向上させるため、入力ストリームの状態フラグを明示的に管理する。特に成績データの検証では、数値範囲のチェックを追加する。
std::istream& operator>>(std::istream& is, Learner& l) {
if (!(is >> l.student_id >> l.full_name
>> l.department >> l.score)) {
is.setstate(std::ios::failbit);
return is;
}
if (l.score < 0 || l.score > 100) {
is.setstate(std::ios::failbit);
}
return is;
}
ストリームポリモーフィズムの応用
std::ostreamを基底クラスとして、コンソール出力とファイル出力を同一インターフェースで処理可能にする。派生クラスstd::ofstreamは暗黙的に基底クラス参照に変換され、汎用出力関数で利用できる。
void export_data(std::ostream& output,
const std::vector<Participant>& data) {
for (const auto& item : data) {
output << item << '\n';
}
}
// 使用例
export_data(std::cout, participant_list); // コンソール出力
std::ofstream file("results.txt");
export_data(file, participant_list); // ファイル出力
例外処理の設計
ファイル操作失敗時の例外処理は、アプリケーション層で一元管理する。具体的にはtry-catchブロック内でエラーメッセージを標準エラー出力に転送し、後続処理を中止する。
try {
auto participants = load_data("input.dat");
sort_by_solutions(participants);
export_data(std::cout, participants);
} catch (const std::exception& e) {
std::cerr << "実行エラー: " << e.what() << std::endl;
}
ソートアルゴリズムの実装
ACMルールに基づくソートでは、解題数の降順とペナルティ時間の昇順を組み合わせる。ラムダ式を使用して比較関数を定義し、std::sortと統合する。
void sort_by_solutions(std::vector<Participant>& list) {
std::sort(list.begin(), list.end(),
[](const Participant& a, const Participant& b) {
if (a.problem_count != b.problem_count) {
return a.problem_count > b.problem_count;
}
return a.penalty_time < b.penalty_time;
}
);
}