C++

引数をポインタで渡すと、保存するのかも???

in

C++の実装で関数の引数をリファレンスにするか値またはポインタにするかについては一応の目安があって

  1. オブジェクトを引数とする場合はリファレンスを使う
  2. 組込型を引数とするときは値で渡す
  3. 関数内で組込型を変更する場合はポインタ渡し

もちろん、変更の有無に関してconst付けたりとか、3.についてchar*で文字列を渡す場合はどうなんだ?(僕の場合文字列を渡すには99%がstd::stringにしてますからあまり考えなくとも済みます)とか他にも考えることはあるのですがまぁおおよそこんなガイドラインで不自由今日までやってきました。ところが、積ん読だったC++ スタイルブック (IT Architects’ Archive―CLASSIC MODERN COMPUTING)という本をパラパラ眺めていたら、

非constの参照パラメータは、その関数がオブジェクトに非const演算を実行する可能性があることを示すが、その関数がオブジェクトへの参照を保存するかどうかは示さない。参照の代わりにポインタを使用して、引数として渡されたオブジェクトへの参照またはポインタを、その関数が格納することを示すべきである。
(中略)
ポインタを使用すると、オブジェクトへの参照が格納される可能性があるというヒントを与えることになる。

恥ずかしながらこれ全然知りませんでした。考えたこともなかったです。基本的には上記のようなガイドライン、つまり受け渡しの効率(と変更の有無)だけに注目してインタフェースを決定していたわけです。しかもなぜポインタで受け渡しすることがオブジェクトへの参照が格納される可能性があることになるのかいまひとつよくわかりません。同書の例にもあるように、

class foo
{
  public:
    foo() {};
    void voice_of_woo() { pw_->voice(); };
    void var(const woo& w) { pw_ = &w ; };
  private:
    const woo* pw_;
};

なんてコードもアリにはありなのでvar()が必ずしも

void var(const woo* w) { pw_ = w ; };

が、関数が「オブジェクトへの参照を保存するだろう」と予測できるわけではないと思うし、オブジェクトへの参照を保存するからといって必ずしも引数がポインタである必要はないと思うのですが....少なくとも、少なくとも僕は、関数宣言だけをみて「wooオブジェクトへの参照が保されるんだな」なんてことは気がつかない。どちらの場合も、ドキュメントやソースコードを読んではじめてその挙動を理解するってことになる気がします。

単なる慣習のことを言っているとも思えませんしもう少し突っ込んだ解説が欲しかったのですが、残念ながらその理由は書いてありませんでした。こんな単純なサンプルで説明できることではなくてもっと深淵な理由を孕んでいる気もしますが無知なる僕にはハッキリとしたワケが解りませんでした。かとにかくすっきりしませんね。

for_eachでメンバ関数を使う時の復習的自分メモ

in

for_eachでFuncにメンバ関数を指定するっていうお題はbins1st、mem_fun/mem_fun_refを使えってことになるのですがそれ以外にも落とし穴があります。なかなかまとめて説明しているものが見つからなかったので自分自身のおさらいを兼ねて...

ちょっと変態的な関数ポインタ

in

メンバ関数のポインタをvectorに突っ込んで使おうとして手間取ったのでメモ。ググってみたらstructに関数ポインタ変数を宣言すれば簡単にvectorに格納できるのはすぐにわかったのだけれど使い方で一晩悩みました。まだまだです>自分。とりあえず、グローバルな関数なら、

C/C++ or Ruby ?

in

近頃はRubyやPythonなんかのスクリプト言語の人気が高くて、人気の秘密が今ひとつ実感できなかったのですが今回のような経験をしてみるとその一端が見えたような気がします。それは、ライブラリの豊富さにあるのだと思います?例えば、今回のように「CSVファイルを読んでMySQLのデータベースを参照し結果を出力する」というたったこれだけの処理をC/C++で書くのに約一日半かかっています。前日に書いたRubyでは約二時間。この差はRubyにはMySQL操作のためのライブラリがあらかじめ用意されていたところにあります。C/C++にはそういうライブラリはありませんから(探せばあるのかも知れませんが)そこのところは自分でなんとかするしかないですよね。そうすると、それだけで半日はたっぷり時間を取られるわけでここらあたりのとっかかりの早さこそが人気の秘密なのじゃないかな?と思います。

1400万行のデータをRubyで扱うと...?(C/C++でリベンジ編)

1400万行のデータをRubyで扱うと...?で玉砕したのでここはC/C++で書いてみることにしました。C/C++の場合、使い捨ても業腹なので簡単なベースクラスを作成し派生クラスで対応することにします。ベースクラスでは今回必要なものだけを実装し、再利用するようなことがあれば逐次追加していくつもりです。(サンプルソースからはエラー処理を端折っています。)

static char* server_args[] = {
  "MySQLBase.cpp","--datadir=/usr/local/mysql/var","--key_buffer_size=32M"
};
static char* server_groups[] = {
  "embedded","server","this_program_SERVER",(char *)NULL 
};
class CMySQLBase {
protected:
  MYSQL*  m_db;
  MYSQL_RES* m_res;
public:
  CMySQLBase(void);
  virtual ~CMySQLBase(void);
  virtual int run(int argc,char* argv[]) = 0;
protected:
  int   init(void); // 初期化処理
  int   end(void);   // 終了処理
  bool  conn(const char* dbname); // コネクト処理
  bool  query(const char* query); // クエリ発行
  void  get_result(void); //結果の取得
  MYSQL_ROW get_row(void); //行の取得
  unsigned int get_field(void); //フィールド数の取得
};

このとき、それぞれのメソッドの実装は以下のとおり。

コンテンツの配信