C++ で関数から文字列をどう返すか

めんどうかつうまい手が見つかりにくい問題なのでちょいと考察。パッと出てくるのは以下の 3 つなんだけど。

  1. std::string object を new して pointer 返し
  2. std::string を値返し
  3. 関数を function object にして内部で std::string を持っておいてそれを参照返し

とりあえず int を std::string に変換して返す num2str() なんかを例に取るとそれぞれ以下のような code になる ( はず )。 header での宣言、実体定義、 test code 、test code の実行結果と続く。

// stringtest.hpp

#ifndef STRINGTEST_HPP
#define STRINGTEST_HPP

#include <sstream>
#include <string>

namespace util {
    namespace stringnew {
        std::string* num2str(const int num);
    }

    namespace stringval {
        std::string num2str(const int num);
    }

    namespace stringfo {
        class Cnum2str {
            private:
                std::string mv_str;
                std::stringstream ss;

            public:
                const std::string& operator ()(const int num);
        };
        extern Cnum2str num2str;
    }
}

#endif // STRINGTEST_HPP
// stringtest.cpp

#include "stringtest.hpp"

namespace util {
    namespace stringnew {
        std::string* num2str(const int num) {
            static std::stringstream ss;
            ss.str("");
            ss << num;
            return new std::string(ss.str());
        }
    }

    namespace stringval {
        std::string num2str(const int num) {
            static std::stringstream ss;
            ss.str("");
            ss << num;
            return ss.str();
        }
    }

    namespace stringfo {
        Cnum2str num2str;
        const std::string& Cnum2str::operator ()(const int num) {
            ss.str("");
            ss << num;
            mv_str = ss.str();
            return mv_str;
        }
    }
}
// main.cpp

#include "stringtest.hpp"
#include <string>
#include <iostream>

using namespace std;

int main(void) {
    const int n = 10;

    string* snew = util::stringnew::num2str(n);
    string  sval = util::stringval::num2str(n);
    string  sfo  = util::stringfo::num2str(n);

    cout << *snew << ": " << sizeof(*snew) << endl
         << sval  << ": " << sizeof(sval)  << endl
         << sfo   << ": " << sizeof(sfo)   << endl;

    delete snew;

    return 0;
}
// VC++ 2008 Express Edition
10: 32
10: 32
10: 32

// MinGW gcc 4.4.0
10: 4
10: 4
10: 4

でまぁ実際書いてみて使ってみての感想なんだけどまず new で作って返すというのはないなぁ。大がかりで注意せざるを得ない object がこういう形で返されるというのなら設計としても使う側としてもまだわかるんだけど文字列みたいな気軽に扱いたいものの始末を使う側が面倒見ないといけないというのはナイ。

他 2 つは一長一短なんだけど使う側に余計な気を回す必要がないという意味で言えば値返し一択。 function object は単純な用途ならそんなに意識する必要はないんだけど num2str() を呼び出すたびに以前の結果が今呼び出した結果で上書きされるということなので 2 回以上使う必要があるという場合はどっちにしても別の変数に結果を退避してやらないといけない。ただまぁ function object はちょいと手を加えると const char* を返せる唯一の候補なので使う側に #include を書かせないで済む ( 使うだけなら組み込み型だけで済ますことができる ) というのが大きな利点。

逆にここらへんの handling は十分に気をつけますから memory 節約させてくださいって場合 ( VC++ だと最低でも 32bite 分の copy が走るのは速度的にもキツい ) は function object か。まぁよほどうまいことやらないときちんと memory 節約できないだろうしそこまで切羽詰まることもそうそうないはずなので無難にいくならやはり値渡し、なのかなぁ。