C
C++

ラッパークラス開発で学ぶ実践C++ その1 準備

More than 1 year has passed since last update.

このドキュメントは連載の初回です。

はじめに

C++で古代のAPI 1 のラッパークラス2を開発します。
その流れの中で、 C++ のうれしさや基本作法を紹介しつつ、クラスの作り方を学んでみよう、という企画です。
言っても、C++11以降を使わ(え)ないので、せいぜい中世くらいまでしかフォローできません。

一応対象は C++ 初級者~ですが、言葉足らずなので全くの初心者はついてこれないかもしれません。

  • 教科書でC++勉強してみたけど、実戦でどう使えばいいかイマイチピンとこない。
  • 今でも C を使っているけど本当はC++が気になっている。
  • 教科書で勉強するより、体で覚えるほうが好き。

という方のお役に立てるかもしれません。

今は素晴らしい文書が山のようにあるので、知識・技術の解説はそちらに任せます。
「実践」というくらいなので、手を動かしつつ読んでもらえると幸いです。

お題 : win32 TLS

Windows API からスレッドローカルストレージ (TLS)のAPI をラッピングしてみます。3

C++11以降はキーワード一発 で使える TLS ですが、古代は API で操作していました。
なのでC++11以降の機能は使いません。4

今回はこちらのサンプルコードを教材として利用させていただきました。

もしTLS知らなかったら、軽く目を通しておいて下さい。

static_cast

個人的に C から来た人に一番最初に憶えてほしいのが static_cast です。
下記のリンク先は、C++キャストの種類や危険性、Cスタイルキャストの邪悪さについて説明しています。

C++キャストはいくつもありますが、ここでは static_cast だけ憶えて下さい。
もし static_cast でコンパイラに怒られることがあったら、他のキャストを検討する前に設計の良し悪しを疑って下さい。

サンプルコードのCスタイルキャストを、static_cast に置き換えてみましょう。
(置き換え後のコードは最後にまとめてお見せします。)

printf をやめてみよう

みんな、そんなに printf が好きですか? iostream 嫌いですか?

iostream がときどき異常に複雑になることは認めます。

ですが printf の %d , %s 等と、引数の型・数・順をぴったり合わせないといけないって、面倒だし、何より安全とは言えませえんよね。
片方直すとき、もう片方も直さにゃならんし。

printf( "TlsAlloc() Failed. gle=%u\n", GetLastError() );

やめて

std::cout << "TlsAlloc() Failed. gle=" << GetLastError() << std::endl;

に慣れてみませんか?

型指定いらないのって、慣れると便利ですよ。
クラス専用の出力を自前で定義できるんですが、これができるとちょっとうれしくなってくるかも。そのうち紹介します。


ということで、教材サンプルコードに手を入れた結果です。

#include <windows.h> 
#include <iostream>   // stdio.h の代わり

// 内容を main() から分離しました。
int tls_test()
{
    DWORD dwIndex = TlsAlloc();
    if (TLS_OUT_OF_INDEXES == dwIndex) {
        std::cout << "TlsAlloc() Failed. gle=" << GetLastError() << std::endl;
        return 1;
    }
    std::cout << "TlsAlloc returned " << dwIndex << std::endl;

    char szMsg[] = "Hello, World\n";
    if (!TlsSetValue(dwIndex, szMsg)) {
        std::cout << "TlsSetValue Failed. glt = " << GetLastError() << std::endl;
        return 1;
    }

    char* szRet = static_cast<char*>(TlsGetValue(dwIndex));
    if (!szRet) {
        std::cout << "TlsGetValue Failed." << std::endl;
        return 1;
    }
    std::cout << szRet << std::endl;

    if (!TlsFree(dwIndex)) {
        std::cout << "TlsFree Failed." << std::endl;
        return 1;
    }
    return 0;
}

int main(int argc, char* argv[]) 
{
    int ret = tls_test();
    // VS で F5 押した時一瞬で終わっちゃわないようにする。
    char c;
    std::cin >> c;

    return ret;
}

実際に書いて実行してみてください。以下が出力結果です。

TlsAlloc returned 1
Hello, World

確保して set して get して解放する。
教材にはちょうどいい基本を押さえたAPIですね。

次回以降、このサンプルコードをリファクタリングしながらラッパークラスを開発していきます。



  1. Win32 API とか POSIX API とか 

  2. wrapper class. あるAPI群を包み込んで(wrap)隠蔽し、使いやすくしたクラスのことをこう呼ぶことにします。一般的な用語だと思ってたんだけど、検索すると Java のプリミティブラッパークラスばかりヒットするので、念のためここで断っておきます。 

  3. SSLの親戚のことではありません 

  4. thread_local 使えで終わってしまいますから。