Boost使ってみた

はじめに

C++を素で使おうとすると割と地獄…だったのは昔の話、
最近(?)はSTLにいろいろ取り込まれて普通に便利になってたけどやっぱりまだまだ足りない
ってことでBoost入れてみた

boost::posix_time

サーバサイドから文字列で飛んできた日時を何とかしたいことは割とよくあるんだけどC++で文字列を操作しようとすると頭がおかしくなって死ぬ
そんなときにboost::posix_time

文字列→time_t

auto t = boost::posix_time::to_time_t(boost::posix_time::time_from_string( "2017-01-01 00:00:00"));

たったこれだけでなんかよくあるyyyy-MM-dd HH:mm:ss形式からtime_t型に!
ちなみにWindowsだと3001年を超えるとしっちゃかめっちゃかになるのでnullの代わりに9999年とかを入れてると使えない。

time_t→文字列

せっかくtime_tにしたけどやっぱり文字列に戻したい。そんなことも稀によくある
そんなときもboost::posix_time

auto simple = boost::posix_time::to_simple_string(today);
auto iso = boost::posix_time::to_iso_string(today);
auto iso_extended = boost::posix_time::to_iso_extended_string(today);

上から
2017-Jan-01 00:00:00
20170101T000000
2017-01-01T00:00:00

となる。欲しいのとちょっと違う…

boost::property_tree

サーバサイドから降ってきたjsonを何とかしたいことは日常だと思う。でも標準だとできない
ってことでboost::property_tree

Deserialize

かんたんにできる

boost::property_tree::ptree pt;
boost::property_tree::read_json(std::stringstream( どこからともなく現れたjsonデータ ), pt);

後はpt.find()でキーの有無を調べたり、pt.get()で値をとったりできる。すごい

Serialize

こっちもわりとかんたんだった

#include <iostream>
#include <boost/property_tree/ptree.hpp>
#include <boost/property_tree/json_parser.hpp>


int main()
{
    boost::property_tree::ptree pt;
    pt.add<std::string>("hoge", "fuga");
    pt.add<int>("piyo", 123);

    boost::property_tree::ptree child;
    boost::property_tree::ptree child_item1;
    boost::property_tree::ptree child_item2;

    child_item1.add("aaa", "bbb");
    child_item2.add("ccc", "ddd");

    child.push_back( std::make_pair("", child_item1));
    child.push_back( std::make_pair("", child_item2));
    pt.add_child( "child", child );

    std::stringstream jsonstream;
    boost::property_tree::write_json(jsonstream, pt, true);

    std::cout << jsonstream.str() << std::endl;
}

これでこんな感じのjsonになる

{
    "hoge": "fuga",
    "piyo": "123",
    "child": [
        {
            "aaa": "bbb"
        },
        {
            "ccc": "ddd"
        }
    ]
}

問題点として素だと数値を入れてもダブルクォートされてしまう。
解決方法は…一番楽なのは通信相手のエンジニアと交渉して文字列で行くことを認めさせよう。おすすめ。

boost::asio

すごーく便利だけどすごーく面倒だった。
特にマルチスレッド周りがつらい。というか別にこれに限らずマルチスレッド周りはつらいんだった。つらい

接続

Windows環境だったので接続HANDLEをWindowsAPIで作成し、
boost::asio::windows::stream_handle.assign()して出来上がり。超かんたん

書き込み


書き込みは割とすんなり行けた int main() { boost::asio::io_service io; boost::asio::windows::stream_handle stream(io); HANDLE handle = /* どこからかHANDLEを持ってくる */ stream.assign( handle ); io.reset(); std::string data = "なんか書き込みたいデータ"; boost::asio::async_write(stream, boost::asio::buffer(data), [callback](boost::system::error_code err, std::size_t size){ // 書き込まれたcallback }); io.run(); }

読み込み

ふつうに読む分には問題はなかった。んだけどプロトコル的な区切り文字(\r\nだった)まで読めばいいのかな?と
read_untilをしてみたら改行を超えてずごって入ってくるの。ナニコレ?
って思ってたんだけどどうも仕様なのね。consume()してポインタを進めてく的な。最初結構ハマった

int main()
{
    boost::asio::io_service io;
    boost::asio::windows::stream_handle stream(io);

    HANDLE handle = /* どこからかHANDLEを持ってくる */

    stream.assign( handle );
    io.reset();


    boost::asio::async_read_until(pipe_, *buffer, "\r\n", [](boost::system::error_code err, std::size_t size) {
        // 読めたら来る
    });

    io.run();
}

余談

なんかググってるとみんなcallbackの受け口をboost::bindとか使ってんのね。
これくらいのcallbackなら別にラムダでいいじゃん。面倒じゃん。