Home > C++ Archive

C++ Archive

C++トリビアルメモ2(std::vectorのデバッグVC)

Love理論届いた。すげぇアレゲ。感想は後日書く。

VCでデバッグしてるとき、std::vectorの中身が見られなくて困った。


std::vector< double > a;
a.push_back(1.0);
a.push_back(2.0);

for (size_t i = 0; i < a.size(); i++) {
    printf("%f ", a[i]);
}

まあ、上のは適当ですが、デバッガでa[0]とかを見ようと思ってウオッチウィンドウに入れても「オーバーロードがありません」とか何とか出て見られない。
もっともこれは2003だけの話かもしれないけど。
以下のようにアクセスできます。
a._Myfirst[0]
a._Myfirst[1]
std::mapも同じように見られるけど、どのキーがどこに入ってるのか分からんから、よく分かりませんでした。
それだけ。

以上

C++トリビアルメモ1

すごい簡単に作れるので作ってみた。
http://kosumi.myminicity.com/
コスミー町です。訪れてくれると育つらしい。

ひさびさにC++をさわるといろいろバグる・ハマる。というのは以前にも言った気がする。

1.クラスの前方宣言とインスタンス
例えばfriendを使う場合、friendしたいクラスを認識するにはfriendする前にそのクラスが宣言されていないといけない。つまり、


class HogeTester;   // 前方宣言

class Hoge {
   friend HogeTester;

private:
   int foo;
   void bar();
};

みたいな感じで型だけを先に宣言する「前方宣言」が必要となる。これを使わないとHogeTesterの中でHogeを使いたいはずだから入れ子になってしまう。
で、これはいい。これはいいんだけど、これに習って例えば内部クラスの定義を下のほうに書きたいなーとか思うとハマる。


class Hoge {
public:
   class Foo;
   Foo bar;

   class Foo {
   public:
      int a;
   };
};

これは無理。barがインスタンスなため、Fooのデータサイズが分からないとコンパイルのしようがないんだろう。よく考えればそりゃそうかもしれないが、Javaとかやってるとこれくらい許してほしいと思ってしまう。
コンパイル可能なのは


class Hoge {
public:
   class Foo {
   public:
      int a;
   };

   Foo bar;
};

あと、以下のような場合はOKっぽい。


class Hoge {
public:
   class Foo;
   Foo *bar;
   Hoge() { bar = new Foo(); }

   class Foo {
   public:
      int a;
   }
};

ポインタのため。

あと2個ほどはまったんだけど、意外と長くなったのでエントリ分けることにする。
ああそうだ、しょーもない話では


double a = 2/3;

としたらaが0になってはまった。スクリプト言語ばっかやってるとこうなる(スクリプト言語でも気をつけろという話だろうが)
正しくは


double a = 2.0/3.0;

小数点をつけないとintに丸められてしまうとさ。

以上

Windowsのハンドルやらファイルオープンやらのリーク?

前にも書いたとおり、VC++を使っている場合はメモリリークは簡単に検出できます。
でもオープンしたファイルをクローズしてなかったり、Windowsハンドルをクローズしてなかったりって言うのは検出できません。まあ、普通はプログラムが終了すればファイルとかはクローズされるかもしれませんが、怪しい場合もあるし、そこはちゃんと責任もってクローズしたほうがいいでしょう。

そういうわけで、面白そうなツールがリリースされていたのでポインタを置いておきます。
オブジェクトリークチェッカー
ヘッダをインクルードするだけという手軽さがいいですね。まだバージョンが0.1のようですが。
ただ、正直に申し上げますと現在VC環境がまだ整っていないので使ってみてません。
取り急ぎご報告まで。ということであしからず。

以上

スタティックの継承

  • 2007-10-23 (火)
  • C++

前のエントリ「忘れないうちにスタティックイニシャライザー」がひどい感じにおかしかったので修正しました。
#includeが&gt;とか使ってなかったから消えてた。あと単純な間違いもあった。
そのついでに、「継承したらどうなるんだろう。」ってのをやってみました。

TestClass.h


template<typename T>
class TestClass {
    static int a;
};
template<typename T>
int TestClass<T>::a = 0;

TestA.h


class TestA : public TestClass<int> {
};

TestB.h


class TestB : public TestClass<int> {
}; 

main.cpp


int main(void) {
   TestA::a = 111;
   TestB::a = 222;

   printf("%d", TestA::a);

   return 0;
}

結果


222

というわけで、しっかりスタティックでした。
もしTestClassのaが翻訳単位だとしたら(?)、TestA::aとTestB::aが違う実体をさしてしまうんじゃないかという杞憂。
だいじょうぶ、どっちも唯一の実体TestClass::aを見てました。

以上

VC++でメモリリークを発見する

やっぱり肩こりはいやだ・・・。

VCを用いている場合、crtdbg.hを使えば簡単にCやC++のメモリリークを発見することができる。
(以上既報)

やり方は簡単です。


#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>

ってな感じでヘッダをインクルードして、main関数の冒頭で


_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); 

を実行すればよろしい。あとはデバッグ実行するだけ。プログラム終了後、出力ウインドウにリークしている箇所が表示されます。
#includeの前_CRTDBG_MAP_ALLOCを定義しておけば該当ソースファイル名もわかります。
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF); の引数はなんだか忘れちゃったので、各々調べてください。

とまあ、こんな感じですが、なんかcrtdbg.hは頭悪いらしく、C++でクラスとかを使ってると上記のままだとリークしている箇所が正しく表示されません。
以下のようにするとOKです。


#include <stdio.h>
#include <stdlib.h>

#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>                // 最後にインクルードしたほうがいい気がする。C++の場合。標準ヘッダの中にnewとかあると変になる??
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)     // これが重要
#endif

int main(void)
{
   char *aznable;

   _CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);

   aznable = (char *)malloc(3*sizeof(char));

   return 0;
}

newを再定義するのが重要です。正しくリーク位置を取得するためには、すべてのファイルでcrtdbg.hをインクルードする必要があり、newの再定義も必要になるので、


#ifndef MEMORY_LEAK_H
#define MEMORY_LEAK_H
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#ifdef _DEBUG
#define new new(_NORMAL_BLOCK,__FILE__,__LINE__)
#endif
#endif

みたいなmemory_leak.hを作ってこいつをみんなでインクルードしようぜ!って感じにするといいかもしんない。

参考文献 http://support.microsoft.com/kb/140858/ja

以上

文字コード変換

rubyやらphpの統合開発環境らしいAptana。デバッグできなさそうなので微妙。Javascriptに関してはなかなか良さそう。

UTF8からSJISへの変換は、PHPとかならさくっとできますが、Cではどうなのか。
Cではきついというか、自分で作らなきゃいけないような気がするけど、WinAPIを使えば、ちょっとましになる。
やり方としては、UTF8⇒UCS2⇒SJIS(MS932)。
つまり、


wchar_t *ucs2;
char *sjis;
int wlength;
int length;

wlength= MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
ucs2 = new wchar_t[wlength];     // たぶん、wlength+1とかいらない。ナル文字まで含んだ「文字数」が上で返る。
MultiByteToWideChar(CP_UTF8, 0, utf8, -1, uc2, wlength);

length = WideCharToMultiByte(CP_ACP, 0, ucs2, -1, NULL, 0, NULL, NULL);
sjis = new char[length];
WideCharToMultiByte(CP_ACP, 0, ucs2, -1, sjis, length, NULL, NULL);

delete[] ucs2;
return sjis;

こまかいパラメータとかは、
マイクロソフトの、こことかここを見るといいと思うよ。

以上

namespaceでクラスメンバを偽装する

  • 2007-07-13 (金)
  • C++

記憶を消せるようになったら、えーと、んーと、消したい記憶なんてないな・・・。

例えば、std::ios::_Openmodeはファイルストリームのオープンモードを指定する引数の型です。
他の環境は知りませんが、VC.NETではそうなってます。
しかーしながら、WindowsCE4.2ではそもそもストリームがないので、std::ios::_Openmodeなんてありません。
したがって、もしstd::ios::_Openmodeをどっかで使っているソースがあるとして、それをCE環境でコンパイルしようとしても無理な話です。(そもそもストリームがないんだから、そんなことをしたらだめだろう、といいたいでしょうがそこは度外視で。)
よって、どーしてもstd::ios::_Openmodeを使いたいんだ!という場合には定義するしかありません。


namespace std {
    class ios {
    public:
        typedef int _Openmode;
    
        static const _Openmode binary = 0;    // vc6.0 だと未対応
        static const _Openmode app = 1;
    }
}

素直にやれば上記のようにすればいいと思われます。std::ios::binaryが使えるはずです。
が、VC6やそれを基盤としているEmbeddedVC4.0では上記のような「static const 整数」のヘッダでの初期化に対応していません。(言語仕様的には”static const 整数型”の場合はヘッダで初期化していい、はず。)
そこでどうするか。


 namespace std {
    namespace ios {
        typedef int _Openmode;
    
        static const _Openmode binary = 0;    // これならヘッダで初期化OKっぽい。staticなので翻訳単位はインクルードファイルに限定される。
        static const _Openmode app = 1;
    }
}

上記のようにnamespaceでごまかせました。std::ios::binaryが使えます。

・・・用途あるのかな。

以上

C++でも正規表現を使いたいよ!本当はCでも使いたいけど!

今はもうない読んだ。まあ、いわゆるひとつの「やられた」。いつものことですが。
萌絵みたいな女性がいたら、一度ぎゃふんと言わされてみたい。

C++で正規表現。
boostとか使えばできますが、boostって結構でかいって言うか、ちょっと正規表現使いたいだけなのにboostの諸々を入れるのは面倒、ということはあるんじゃないかと思います。
で、便利じゃないかと思ってるのがGRETAです。
(2010/05/20 ↑消えたっぽい。とりあえずこっち。)
VCで使うという条件で、商用利用もフリーで可だったと思われるライブラリです。
簡単な使い方だけ示しておきます。(要望があれば多少詳しく説明します。)


#include < iostream >
#include < string >
#include "regexpr2.h"

int main(int argc, char *argv[]) {
    regex::match_results results;  // 結果格納用変数
    string str("abcdefg12345hijk"); // 検索対象文字列

    regex::rpattern pat("\\d+(\\w+)");  // 正規表現。\\は2個要るよ!
    regex::match_results::backref_type br = pat.match( str, results );  // マッチ。brはマッチした部分が入る。br=="12345hijk"
    std::cout << br << std::endl; // 12345hjik
    regex::match_results::backref_vector all_br = results.all_backrefs();  // 後方参照をするためのvector。
    std::cout << all_br[0] << std::endl; // 12345hjik
    std::cout << all_br[1] << std::endl; // hjik


    regex::rpattern subst("\\d+", "zzzz", regex::GLOBAL);  // 置換定義。置換前、置換後、パラメータ。
    regex::subst_results substitute_results;
    subst.substitute(str, substitute_results);
    std::cout << str << std::endl; // abcdefgzzzzhijk

    return 0;
}

wstringを使いたい場合はbasic_rpatternなどがあります。
置換はパラメータをいろいろ与えることで、全部置換とか最初の一個とか指定できます。
また、置換だけでなくsplitとかもあります。
注意事項としては、GRETAは完全なテンプレートライブラリというわけではなく、regexpr2.cppとsyntax2.cppをコンパイルしてリンクする必要があります。

以上

[C++]オペレータをオーバーロードする

  • 2007-07-09 (月)
  • C++

先日の話ですが、「戦国無双Wave」がAmazonで予約可能になりました。
やっとですか。しかも、内容的にはどうなんでしょう。微妙な気が・・・。

で、オーペレータ。簡単な話ですが、(友人に)聞かれたので答えておきます。(ここのアドレス教えてないけど。)


template< typename T >
class Hoge {
private:
    std::vector< std::vector< T > > internal;

public:
    std::vector< T > operator[](size_t index) {
        return this->internal[index];
    }
};

悲しいですね。上記の場合、returnで帰ってくるのはinternal[index]をコピーした新しいインスタンス(std::vector< T >型の)なので、思ったとおりの動作はしません。参照を返しましょう。


    std::vector< T >& operator[](size_t index) {
        return this->internal[index];
    }

・・・なんか、すごいくだらないな。。基本過ぎる。
仕方がないので、上記のようなものとして↓をあげときます。


template< typename T >
class Hoge : public std::vector< std::vector< T > > {};

これで十分動く。

以上

サービスって簡単に・・・つくれるのか?

これはひどい
すごいねこれは。ひどい。
そもそも出てきた瞬間から完成度高い。どっかでこっそり暖めてたんだろうか。
デザインがいい(まあ、ほぼDiggだけど)。よくできとる。

一方、私のほうは、・・・なかなか無理やね。
CakePHPで作ると、どうも大げさになる気がする。一向に完成する気配がない。
やっぱCakePHPは、大規模なサービスか、scaffoldで済むくらい小規模なものに向いているんだろうか。

そんな感じですが、ちょっとだけC++のメモを書いておく。
テンプレートクラスの明示的なインスタンス化(特殊化)。C++テンプレートの私的注意で書いたけど、具体的には書いてなかったから。


template< typename T > class Hoge {};

// ↓明示的なインスタンス化。
template class Hoge< int >;

ってヘッダに書いとけばいい。

Home > C++ Archive

Search
Feeds
Meta
 合計:018987
 今日:0126 昨日:0157

Return to page top