プログラム関連


FrontPage

C++

例外をもちいたassertの実装

単なる例外処理よりもこっちのほうが良さそう
http://monpe.cliff.jp/computer/cpp/330_cpp_ed_doc.html

#include <iostream>
using namespace std;
template <class A, class T>
inline void Assert(A assert_arg, T except)
{
if (!assert_arg) throw except;
}
void main() {
int i_a;
int i_b;
int i_except;
cout << "オペランド1:";
cin >> i_a;
cout << "オペランド2:";
cin >> i_b;
try {
Assert(i_b!=0, i_except=10);
cout << "結果:" << i_a/i_b << endl;
}
catch(int i_catch){
cout << "0で割り算を実行しました" << endl;
}
}

C++によるゼロ割例外処理

http://www.hiroshima-cu.ac.jp/japanese/IPC/hunet99/sun/WorkShop/ja/html_docs/c-plusplus/c++_ug/exception.doc.html
http://www.geocities.jp/ky_webid/cpp/language/025.html
http://www.bugbearr.jp/?C%2B%2B%2F%E4%BE%8B%E5%A4%96

例外クラスのthrowの方法

http://www.02.246.ne.jp/~torutk/cxx/exception/programming.html

サンプル

http://www.deitel.com/articles/cplusplus_tutorials/20060325/cplusplustutorial_DivideByZero_Page2.html

  • .h
    // Class DivideByZeroException definition.
    #include <stdexcept> // stdexcept header file contains runtime_error
    using std::runtime_error; // standard C++ library class runtime_error 
    // DivideByZeroException objects should be thrown by functions
    // upon detecting division-by-zero exceptions
    class DivideByZeroException : public runtime_error
    {
    public:
       // constructor specifies default error message
       DivideByZeroException();
    }; // end class DivideByZeroException
    //Fig. 16.1 Class DivideByZeroException definition.
    DivideByZeroException::DivideByZeroException()
       : runtime_error( "attempted to divide by zero" ){
    }
  • .cpp
    // Fig. 16.2: Fig16_02.cpp
    // A simple exception-handling example that checks for
    // divide-by-zero exceptions.
    #include <iostream>
     using std::cin;
     using std::cout;
     using std::endl;
    #include "DivideByZeroException.h" // DivideByZeroException class
    // perform division and throw DivideByZeroException object if
    // divide-by-zero exception occurs
    double quotient( int numerator, int denominator )
    {
       // throw DivideByZeroException if trying to divide by zero
       if ( denominator == 0 )
           throw DivideByZeroException(); // terminate function
       
       // return division result
       return static_cast< double >( numerator ) / denominator;
    } // end function quotient
    int main()
    {
       int number1; // user-specified numerator
       int number2; // user-specified denominator
       double result; // result of division
       cout << "Enter two integers (end-of-file to end): ";
       // enable user to enter two integers to divide
       while ( cin >> number1 >> number2 )
           {
              // try block contains code that might throw exception
               // and code that should not execute if an exception occurs
               try
                   {
                       result = quotient( number1, number2 );
                       cout << "The quotient is: " << result << endl;
                   } // end try    
               // exception handler handles a divide-by-zero exception
               catch ( DivideByZeroException &divideByZeroException )
                   {
                       cout << "Exception occurred: "
                            << divideByZeroException.what() << endl;
                   } // end catch            
               cout << "\nEnter two integers (end-of-file to end): ";
           } // end while
       cout << endl;
       return 0; // terminate normally
    } // end main
    /*
    Output
     Enter two integers (end-of-file to end): 100 7
     The quotient is: 14.2857
     Enter two integers (end-of-file to end): 100 0
     Exception occurred: attempted to divide by zero
     Enter two integers (end-of-file to end)
    Copyright 1992-2006 by Deitel & Associates, Inc. All rights reserved.
    */




boost/thread.hppでマルチスレッドプログラミング

単純な場合

#include <iostream> 
#include <boost/thread.hpp>
#include <boost/bind.hpp> 
using namespace std; 
using namespace boost; 
// 引数なし関数をマルチスレッドで実行 
const int kCount =  100000000; 
const int kInterval = 1000000; 
void PrintHello() { 
    for(int i = 0; i != kCount; ++i) 
	if (!(i % kInterval)) cout << "Hello "; 
   } 
void PrintWorld() { 
   for(int i = 0; i != kCount; ++i) 
	if (!(i % kInterval)) cout << "World! "; 
} 
int main() { 
   thread thr_hello(&PrintHello); // PrintHello関数を実行するスレッドの生成、実行 
   thread thr_world(&PrintWorld); 
   thr_hello.join(); // thr_helloが走らせているスレッドの終了を待つ 
   thr_world.join(); 
   return 0; 
 } 

メンバ関数を使う場合

#include <iostream> 
#include <boost/thread.hpp>
#include <boost/bind.hpp> 
using namespace std; 
using namespace boost; 
// メンバ関数をマルチスレッドで実行 
class PrintMessage { 
public: 
   PrintMessage(const char* msg)
	:kMessage_(msg), kCount_(100000000), kInterval_(1000000) {} 
   void run(); 
private: 
   const int kCount_; 
   const int kInterval_; 
   const char *kMessage_; 
}; 
void PrintMessage::run() {
    for(int i = 0; i != kCount_; ++i){ 
	if (!(i % kInterval_)){
	  cout << kMessage_;
	}
   }
} 
int main(){
   PrintMessage hello("Hello "); 
   PrintMessage world("World! "); 
   thread thr_hello(bind(&PrintMessage::run, &hello)); 
   thread thr_world(bind(&PrintMessage::run, &world)); 
   thr_hello.join(); 
   thr_world.join();
   return 0; 
}  

参考

C++プログラムの実行時間計測

unix環境ならgettimeofday
windows環境ならWIN32APIの関数を調べる

参照ウェブサイト:http://kzk9.net/column/time.html


Nさんが教えてくれたSTLのためになる話

継承される基本クラスのデストラクタにはvirtualをつける。

C++のクラスは継承されることを前提として作る。

しかしSTLのクラス(vector,deque,string,map 等)は継承されないことを前提として作られている。

したがって、STLのクラスを継承するのはあまりよろしくない。

継承するのでは無く、クラスのメンバ変数としておくのが望ましい。
(オブジェクト指向におけるIs-aとHas-aの関係・・だそうだ)

STLのdequeを使った動的二次元配列の作りかた

vectorの方がアクセス時間が少々早いようだが、
vectorはpush_front(),pop_front()を持っていないので
dequeを使った。

変数:val, 行数:row, 列数:col

・宣言

 0×0の行列 val
 deque< deque<double> > val;
 (row,col)行列 val
 deque< deque<double> > val(row, deque<double>(col));

・要素の追加

 deque<double> val1;
  //末尾行に追加
  val.push_back(val1);
  //先頭行に追加
  val.push_front(val1);
  double val2;
  //列に追加
  val[row].push_back(val2);
  val[row].push_front(val2);
 

・要素の削除

  //末尾行を削除
  val.pop_back();
  //先頭行を削除
  val.push_front();
  //列を削除
  val[row].pop_back();
  val[row].pop_front();
 

・宣言後のサイズ変更

  deque< deque<double> > val;
  val.resize(row);
  for(unsigned int i=0; i < val.size(); i++){
    val[i].resize(col);
  }

stringstreamの使いかた

数値をそのままの形で文字列に変換するときに便利です。

参照ウェブサイト
http://ppwww.phys.sci.kobe-u.ac.jp/~akusumoto/program/detail.php?d=c/10-other/sstream_trap

string型とcharポインタ型の関係について

 C++のstring型は便利だ(当たり前か?)

面白いことに気づいたので、覚え書きでも少々書いてみます。

string型からcharポインタ型への変換 [#eb02a673]

string str = "str";
char* ch;
ch = str.c_str();

charポインタ型からstring型への変換 [#ac7bab70]

char* ch;
string str = ch;

charポインタ型文字列とstring型文字列の結合 [#u7b497d9]

char* ch = "char";
string str = (string)ch + "str"; 

char配列型文字列ってstring型でキャストできるんですねえ・・
でも無理矢理な方法のような気がするのでだれか正当な方法を見つけてください。

JAVA


JDK5の新機能(多すぎる)

List,Vector,DequeなどのCollectionインターフェイスにジェネリクスが導入された。
簡単に言うと、C++のtemplateと良く似た機能がJavaに追加された。

ラッパークラスInteger,Double, ・・ から基本型 int, double,・・ との間の変換が自動的におこなわれるようになった。

Staticクラスをインポートできるようになった。
Mathクラスをインポートすれば、 Math.PI, Math.sin()などのMath.を省略できる

新機能ではないが、getenv()が非推奨メソッドじゃなくなっている

OpenHRP3 の Common ディレクトリででるjavaの警告を消す方法

Common/corba/Makefile.common

を書き換える。
警告がでる原因は、
JDK5付属のjavaidlコンパイラidljにより生成されるソースコードが JDK5の新機能に対応していないこと。
対応させるために、Makefile内部でgrepをかけました。
下に添付しておきますが、非保証です。

OpenHRP3 の ModelLoader?ディレクトリででるjavaの警告を消す

ModelLoader/server/ObjectStruct.java

を書き直す。
やっちゃいけないことをしているのかもしれない。
でも一応添付
警告はでていないけど表記統一の関係上VrmlSceneEx?.javaも添付
勿論非保証

OpenHRP3のclientディレクトリででるjavaの警告を消す

client/gui/com/generalrobotix/ui/util/AlertBox.java

を書き直す。
これもまた変なことが起こりそうで怖い
でも一応添付
勿論非保証

JMstudio windows版での注意

Javaのアップデートをすると突然動かなくなる。


JMstudioを使う方法

JMFをインストールするとjmstudioというmovを再生したり、 movをaviに変換できたりする便利なソフトウェアがついてくる。

Vine3.2なら、JMFをインストールしたディレクトリ/binの下で

./jmstudio

と打てばjmstudioが起動したのだが
Ubuntu 7.04 Feistyの場合、JMFをインストールしたディレクトリで

java -Dawt.toolkit=sun.awt.motif.MToolkit JMStudio

FedoraCore6ではもっとめんどくさい
1, libXp.so.6というライブラリをyumでインストール

# yum install libXp.so.6

2, $(JMFHOME)/bin 以下で

$(JAVA_HOME)/bin/java -Dawt.toolkit=sun.awt.motif.MToolkit JMStudio


FedoraCore6の場合は動かすまでに相当苦労した。
気づいたきっかけは
・java.lang.UnsatisfiedLinkError? という Exceptionが発生し Can't load IA 32-bit .so on a IA 32-bit platformというエラー文が出力された ことを手がかりにGoogle先生とお話することにより、
jdk5 version10以降はエラー文がおかしい という謎の記述を見つけたこと
・私のFedoraCore?にjdk5のversion6が入っていたこと
そしてエラー文を一所懸命に読んで、
・libXp.so.6が足りないということがわかったこと
・FedoraのレポジトリにlibXp.so.6が存在していたということ
です

bash

パスの設定

/home/.bashrc

に追記する。

例えばこんな感じ

export JAVA_HOME=/usr/java/jdk1.5.0_11
export PATH=$PATH:$JAVA_HOME/bin

ファイルの文字列を一括変換する

grep -lr 検索文字列 検索対象ファイルのディレクトリ | grep -v '検索から除外するパス' | xargs sed -i 's/検索文字列/置換後の文字列/g'

シェルスクリプトに実行時引数を可変長であたえる方法

実行ファイルの最後に "$*" と書いてあげれば良い。

例えば、こんな感じ

$ ./client $NS_OPT $*

ターミナルの出力結果をテキストファイルに落とす方法

出力前に、ターミナルで

$ script

とタイプしておき、その後

$ (出力コマンド)

として出力する。

出力が止まったら、ターミナルで

$ exit

と打つ。 そうするとtypescriptというファイルが出来る。 これにはscriptを実行した後のターミナルの入出力が全て記録される。

CORBA

outパラメータ引数として取る場合

_out型にマッピングされるので、 毎度おなじみの_var型を使って領域を確保する。
あとはほとんど下に書いてあるのと同じなので、
めんどくさいから書かない。
注意としては、下と同様にポインタ演算で要素にアクセスするということ。

戻り値に可変長Sequenceの配列型を取る場合

最近CORBAのキモさに対して快感を覚えてきた。
機関銃をぶっぱなす女子高生の如く・・・
Sequence型の配列を戻すような場合、
_slice*型を取り扱わなければならない。

こんなときも万能スマートポインタ(見たいなもの)_var型 変数が活躍する。

ただし、[]演算子がオーバーロードされてない(そのくらいしとけ、omniのアホ)
のでポインタ演算のお勉強が必要

CorbaServerClient::DblSequence3_slice*
CorbaServerClient::CorbaServer_impl::
returnDblSeq2(const CorbaServerClient::DblSequence& seq){
   CorbaServerClient::DblSequence3_slice* seq3_ptr;
   CorbaServerClient::DblSequence3_var seq3_var;
   seq3_var = DblSequence3_alloc();
   for(int i=0; i<3; i++){
       (*(seq3_var + i)).length(seq.length());
       for(int j=0; j<seq.length(); j++){
           (*(seq3_var + i))[j] = seq[j];
       }
   }
   
   seq3_ptr = seq3_var._retn();
   return seq3_ptr;
}

別PCにサーバを立てたときにサーバ側の関数の終了をクライアントが待たないようにする

idlで関数の戻り値の前にonewayキーワードを付ければ良い。
ただし、戻り値はvoid型で引数はinパラメータのみ
という制限がつく

oneway void server_method(in short param);

sequence型の受け渡しについて

Sequence型はキモい。 お約束どおりに書いてあげないと領域確保に失敗して、

セグメンテーションエラーやメモリリークが発生する
DynamicsSimulator_impl.cppのおかげでなんとかお約束がわかった。
CORBAの資料ってスクネエなあ。 なんとかならんものかなあ。

  • IDL
    struct Gait{
           double x;
           double y;
           double z;
    	double sstime;
    	double dstime;
    };
    typedef sequence<Gait> GaitSequence;
    void getGait2(out GaitSequence gait_seq);
    	
  • サーバー側
    void SwissRanger_impl::getGait2(OpenHRP::GaitSequence_out gait_seq_out){
       GaitSequence_var gait_var = new GaitSequence;
       gait_var->length(gaitv.size());
       if(gaitv.size() > 0){
    	for(int i=0; i<(int)gaitv.size(); i++){
    	    gait_var[i].x = gaitv[i].x;
    	    gait_var[i].y = gaitv[i].y;
    	    gait_var[i].z = gaitv[i].z;
    	    gait_var[i].sstime = gaitv[i].sstime;
    	    gait_var[i].dstime = gaitv[i].dstime;
    	}
       }
       gait_seq_out = gait_var._retn();
    }
  • クライアント側
    SwissRanger_var sr;
    void SwissRangerClient::getGait2(std::vector<OpenHRP::Gait>& gait_v){
       OpenHRP::GaitSequence_var gait_var;
       sr->getGait2(gait_var);
       gait_v.resize((int)gait_var->length());
       for(int i=0; i<(int)gait_v.size(); i++){
    	gait_v[i].x = gait_var[i].x;
    	gait_v[i].y = gait_var[i].y;
    	gait_v[i].z = gait_var[i].z;
    	gait_v[i].sstime = gait_var[i].sstime;
    	gait_v[i].dstime = gait_var[i].dstime;
       }
    }