C++ Tips その1

前置き

かなり以前に作つたまま放置してゐたが、さすがに情報が古すぎるといふか、今となつては推獎すべきではないことを獎めてゐたりもしたので、このたび手を入れた。

令和元年8月26日記す。

文字列の入力

平成20年當時、標準入力から一行毎に讀み込んでゆく例として次のやうなコードが出回つてゐたことについて云々した。

#define BUFSIZE 256

std::string allString;
while (cin.good()) {
    char buf[BUFSIZE];
    std::cin.getline(buf, BUFSIZE - 1);
    allString += buf;
    allString += "\n";
}  

固定バッファで取り込むのなんかダサいみたいなことを書いて、次のやうなコードを提示した。

std::string allString;
while (cin.good()) {
    std::string line;
    std::getline(std::cin, line);
    allString += line;
    allString += "\n";
}

ダサいと書いたが、最初の例だと、1行の入力文字數が255文字を超えると入力には無かつた改行コードが入る、といふのがいかにも拙い。255文字を超えないと分かり切つてゐるなら、固定バッファを使ふメリットがあるかも知れないけれど、いつでもどこでもさういふ前提を置けると思ふのは、どうなんだらう。元々固定長ではないものを扱ふのなら、可變長なものを使つてすつきりしたコードを書いた方がいいのではなからうか。

std::stringの+=演算子を使ふのは果たしてどうなの、といふのはあると思ふ。オーソドックスにstd::ostringstreamを使ふなら、こんな感じか。

std::ostringstream oss;
while (cin.good()) {
    std::string line;
    std::getline(std::cin, line);
    oss << line << '\n';
}
std::string allString = oss.str();

Noncopyableについて

平成20年當時はC++11のなかつた時代なので、インスタンスのコピーを禁止する方法として、コピーコンストラクタと代入演算子をprivateで宣言し、未定義のままにする、といふ方法が流布されてゐた。コードで示せば次のやうな感じ。

class NonCopyableA
{
// ...
private:
    NonCopyableA(const NonCopyable &);  // 宣言のみ
    NonCopyableA& operator=(const NonCopyable &);  // 宣言のみ
// ...
};  

また、當時既にBoostのnoncopyableが利用可能であつた。例を擧げると次のやうな感じ。

#include <boost/utility>  // for boost::noncopyable

class Hogehoge : boost::noncopyable
{
// ...
};

int main()
{
    Hogehoge h1, h2;
    h1 = h2;  // 代入出來ないのでこれはNG
    Hogehoge h3(h1);  // コピー出來ないのでこれもNG

// ...
}  

令和元年の現在、我々はC++11どころかC++17だつて使へる。といふことで、散々既出な氣もするが、そんなことを物ともせずに最初の例の修正を示す。

class NonCopyableA
{
// ...
public:
    NonCopyableA(const NonCopyable &) = delete;
    NonCopyableA& operator=(const NonCopyable &) = delete;
// ...
};  

いや、別に前のままでも實際上の問題はないのよ、多分。

Noncopyableについて輕く檢索を掛けてみたら、boost::noncopyableをprivate繼承するといふ方法は、多重繼承が絡むと些かの問題を含むといふ情報があつた。

これを踏まへてNoncopyableを書いてみたのが、以下。

template<class T>
class Noncopyable
{
public:
    constexpr Noncopyable() = default;
    ~Noncopyable() = default;
    Noncopyable(const Noncopyable&) = delete;
    Noncopyable& operator=(const Noncopyable&) = delete;
};

これをprivate繼承してnoncopyableなクラスを定義するには、次のやうにする。

class A : Noncopyable<A>
{
// ...
};

バインド

函數(ないし函數オブジェクト)を引數として渡す際に、一部の引數に固定値を與へたい場合といふのが、時々ある。あるいは、特定のオブジェクトについてのメンバ函數の呼び出しを函數オブジェクト化したいといふこともある。

平成21年當時、さういふ時に使ふべきものとしてboost::bind()を紹介したのだが、令和の御代となつた現在では非推獎。C++14を手にした我々はlambda式を使ふべきである、と、S. Meyers『Effecctive Modern C++』にある。

とても簡單な例を以下に示す。

class Foo
{
public:
    int baz(int x) { return x * 2; }
};

template<class Func>
int bar(int x, Func f)
{
    return f(x) * f(x + 1);
}

int main()
{
    auto foo = Foo();
    auto g = [&foo](int i) { return foo.baz(i); };  // g は foo.baz() を函數オブジェクト化したもの
    std::cout << bar(2, g) << std::endl;

    return 0;
}