C++相談室 part10

このエントリーをはてなブックマークに追加
465デフォルトの名無しさん
http://do.sakura.ne.jp/~junkroom/cgi-bin/megabbs/readres.cgi?bo=lounge&vi=1027870433&res=19
こいつを
BigNum a;
a = 10;
cout << a.ToInteger() << endl;
というような感じでやったんですが、ToInteger()を2回以上呼び出すとおかしな値になります。
ずいぶん悩んだんですが、原因がわかりません。
ちなみにVC++6.0です。
オブジェクト指向:堺
オブジェクト指向:蜀
>>465
operator=などが一時オブジェクトを生成

デフォルトコピーコンストラクタが呼ばれる

一時オブジェクト消滅

一時オブジェクトのデストラクタが呼ばれる。

Num配列あぼーん

もとのオブジェクトがNum配列参照

プログラムあぼーん
469465:02/09/02 22:03
>468
なんとなく感じ分かりました。ありがとう御座います。
>>468
最低な言語だな。
>>468
そだね。return *this の時にコピーコンストラクタが呼ばれるのが原因だね。
なんちゅうややこしい言語なんだ。
auto_ptrとかshared_ptrにすれば解決じゃん
なんでこんな単純な物をテンプレートまで持ち出して複雑にしなくちゃならないんだよ。
自前でコピーコンストラクタを書いてやれば解決すます。それだけ。

Effective C++の11項「メモリを動的に割り当てるクラスでは、コピーコンストラクタ
と代入演算子を宣言しよう」当たりを参照。
Bignumをそれなりに実装しようとしたら
結構複雑になりますが何か。
> テンプレートまで持ち出して
テンプレート使うのがそんな大そうな事か。つかコーディング楽になるもんだろ。
わざわざ頑張らんでもとりあえずはvector<int>で十分だろ。

>>472
shareしたりauto_ptrで破壊したりしちゃったらダメだと思ふ…

 (´Д`;)ヾ 473はこれからtemplateやSTL覚える人なんでかんべんしてください。
   ∨)
   ((
>>476
>>465の問題は他の言語では何もしなくてもコーディングが楽ですがなにか?
C++は普通レベルに使えるまで長くかかる言語だなぁ。templateやSTL必須か。
まさかtemplateやSTLは上級レベルとか言わないよね。
>>479
>>465の問題なんかどうでもよくて
テンプレートのことについて話してるんですが何か?
>>477
465の問題についてはって事。
>>481
俺は>>465の問題について話してる。これについては否定はしないようだね。
テンプレート自体は「テンプレートは何のためにあるか?」の答え通りに
使えば便利なのは良く分かっている。

 (´Д`;)ヾ すいません
   ∨)  他の言語は>>465みたいなオブジェクトのコピーはどう行われるのか
   ((    このC++厨に教えてください
>>477
俺も vector 使うに一票だが auto_ptr 使うのは、コピーコンストラクタをきちんと
書くという条件の下では、問題ないと思うぞ。shared_ptr も参照カウントをチェック
して copy-on-write できるし。

>>479
楽な分だけ、代償は支払ってるけどな。
>>484
他の言語が何をさすかわからんがJavaやC#等はポインタ(参照)はshared_ptrとか適当なことを言ってみるテスト。
487質問君:02/09/02 23:44
operator=とかの宣言方法なのですが、
const CTimeEx& operator=(time_t t);
のようになっている場合があるかと思うのですが、
この最初のconstってどういうことなのでしょうか?
戻り値のCTimeExの参照についてconst指定するって
いうのは、thisがconst?などと考えてしまうのですが
いかがでしょう?
無知ですみませんが、気になって仕方ないので...
戻り値が変更不可能ということ
thisが指してるオブジェクト(*this)が const
C++4年目でSTL勉強し始めた俺は逝って良しですか?
>>490
VC使ってれば使わない罠
492C++初心者:02/09/03 00:00
C++で一度実行をしてexeファイルを作ってから、
プログラムを書き換えてもう一度実行しようとすると

書き込みモードで Debug/Sample1.exe を開けません

ってエラーが出るんですが原因として考えられるのはどんなことがあるんでしょうか?
493質問君:02/09/03 00:02
resありがとうございます。
戻り値または、*thisが変更不可能ということは、
定義内で、*thisに代入とかはできないことになるのですか?
それとも、戻り値が返された後、代入されたくないときに
指定するということですか?
実行中
>>493
constになるのはreturnを受けた側の話
>>493
>定義内で、*thisに代入とかはできないことになるのですか?
ではなく、単純に返却値を定数扱いするということ。
497質問君:02/09/03 00:25
ふむふむ、なるほど、そういうことでしたか!
でも、returnを受けてそれに代入不可能
とかしたいということがあるんでしょうか?
具体的にはa=b=cとかしたくないってことですか?
というか、const指定するのが一般的なんでしょうか?
数値をクラスとして考えると
1 + 2 = 1 だめ
a + b = c いい(const無し)
a + b = c だめ(constあり)
=演算子の返却値を const にするのは代入の途中で値が変わらない
ことを保証するため。a=b=c で c と a の値が違ってたら困る。
500
501質問君:02/09/03 00:39
いろいろ細かいことに答えてもらい
ありがとうございました。
日々精進します(^^;
>>492
実行したのを終了しなきゃね。
503デフォルトの名無しさん:02/09/03 09:36
=演算子のconst性は(a=b)=cには関係するが、
a=b=cには無関係。
>ことを保証するため。a=b=c で c と a の値が違ってたら困る。
auto_ptrわ?
>自前でコピーコンストラクタを書いてやれば解決すます

それより
operator =() の戻りが、参照になってないから、一時オブジェクトがつくられちゃうってだけでしょ。
506デフォルトの名無しさん:02/09/03 14:54
void foo(A &x);
foo(a = b);
という場合、const A &operator=()ならエラーになるけど、
A &operator=()なら通る。あと、intの場合(i = 0) = 1
は正当だから、i = 0は左辺値になる。だから、constは
この場合付けない方がいい。
constは付けない(前スレで既出だった気がする)
理由はEffectiveC++読むこと
>(a=b)=c
>(i = 0) = 1
これは不定じゃないか?
509デフォルトの名無しさん:02/09/03 16:32
newをmallocみたいなものだとした場合、これに対するreallocみたいなものはないですよね?
510702:02/09/03 17:30
>>509
STL使ってれば全然そんなこと考えない。
>>510
702って何だろう?801みたいなもんか?072の間違い???
STLコンテナのresize?
ふつーにvectorでいいんでない?
>>509
ありません
vectorは重いからイヤです
おまえらnewで何の領域を取りたいのか聞けよ
効いてほしけりゃはじめからそう書け
>515
貴様は本当に計ってみたのかと小一時間・・
519デフォルトの名無しさん:02/09/04 10:23
そりゃ関数の引数や戻り値にそのままvector使ったりしたら重いわな。
そういう用途ならauto_ptrでも使っとけ。
ローカル変数やメンバ変数にするなら、重いはずは無い。
処理系によっては、むしろ型の情報を使った最適化が行われていて、
速くなるかも知れない。
何か理由があって、vectorを使えないなら、生のメモリが欲しいのか、
コンストラクト済のメモリが欲しいのかによってやり方は変わる。
前者なら直接malloc/realloc呼ぶのが正解。後者なら、もう1つ配列を
new[]して地道にコピーするのが正解。
malloc->construct->reallocでも良さそうだけど、reallocは
コピーコンストラクタを呼ばないで、単にメモリコピーをしてしまうから、
正しい挙動にするには、malloc->construct->malloc->construct->free
という手順を踏まなければならない。つまり、reallocみたいにコピーを
省略するのは無理。それならnew[]の方がまし。
520デフォルトの名無しさん:02/09/04 11:50
あるプログラムのデバッグをしているのですが
必ずある時点でAborted(core dumped)
となって止まってしまいます。
通常のデバグの方法ではなかなか原因が検出できなくいきづまってしまいました

そこでcygnin上で動かしているgccが吐く
***.exe.stackdumpを調べれば原因がわかるかもと思っているのですが、
ちょっと読み方がわかりません。
これの便利な使い方ってどうやるのですか?
ちなみに簡単なアセンブラやレジスタの仕組みなどはわかります。
>>520
どうせスレ違い厨には分からないだろ。
>>520
gdbだ. ヒントだけあげるから自分で調べて.
523デフォルトの名無しさん:02/09/04 21:02
SDKのファイル・フォルダセキュリティ設定に関して質問があります。
AddAccessAllowedAceEx関数を使用し継承を設定したのですが、設定したフォルダの中に新しいフォルダを作成すると「継承元なし」のフォルダが出来てしまいます。
継承元を親フォルダに設定するにはどうしたらよいでしょうか?
OSはWindowsXPで、VC++のバージョンは6.0です。
>>523
スレ違いだボケ
win32apiスレに行け
525デフォルトの名無しさん:02/09/04 23:11
class A {
int a;
int b;
void show() { printf("a:%d b:%d", a, b); }
};

上のようなクラスがあり、そのインスタンスを複数作った場合、
show()のためのメモリも複数確保されるのでしょうか?

厨な質問ですみません。
二つの自然数a,bの最大公約数を求めるプログラム
>>525
show()自身により消費されるメモリはそのコード本体のみ。
インスタンスを作ろうが作るまいが関係ない。
>>527
クラス内に関数を定義するとinline宣言だから違うかもよ?
もっともクラス毎ではなくて、呼び出し毎になるが。
>>526
ユークリッドの互除法か?それが何か?
>>528
inlineされたとしても、コード本体のみ
という表現に間違いはないと思いますが...
>>530
んだね。スマソ。
532デフォルトの名無しさん:02/09/05 01:53
#include <iostream>
class A{
public: A(){m_a=3;}
protected: int m_a;
};
class B{
public:int func(){
  class fl_A: public A{
  public:
    void operator=(const A &in_A){
      A *a_A = this;
      *a_A = in_A;//ダメポ… }
    int Get_m_a(){//B::m_A::aにアクセスしたいけど、friend関数は使いたくない。
      return m_a;
    }
  };
  fl_A a_flA = m_A;
  return a_flA.Get_m_a();
}
private: A m_A;
};
int main(){
  B a_B;
  std::cout<< a_B.func()<<std::endl;;
  return 0;
}
クラスBのメンバのインスタンスAのprotectedなメンバにアクセスしたいのですが、
friend関数を使わずに無理やり実装したのですが、
多分、処理系依存とかだと思うのですが、どういう風にコンパイラは解釈するのでしょうか…
おとなしくfriend使って実装するつもりですが、気になったので教えてください。
533532:02/09/05 01:55
間違えました。
fl_A a_flA = m_A;

fl_A a_flA;
aflA = m_A;
初期化と代入を間違えました。
>>532
int func()内の、fl_A a_flA = m_A; だけど、これはコピーコンストラクタがないと
コンパイルできないよ。

fl_A a_flA;
a_flA = m_A;

と二行に分けたら?
あららら
>>532
処理系依存と書きながら処理系を指定しないのはどうして?
>>536
と言うか、文法上?の誤りを指定して欲しかったのかな…

この書き方だとコンパイラーがこういう風に解釈しても構わないから、
こう言う風になってバグが発生するみたいな…

一応コンパイラーはMS Visual C++ Professional 6.0 sp5を使っています。
それだったら、コンパイラはデータメンバのうちpublicとprivateの順序を
自由に変えてよいから、fl_A a_flAとA m_Aの順序が入れ替わるかも
しれない、というのはダメ?
>>538
良いです!
つうかそんな卑怯な仕様があったのですか(笑)
なるほど
それなら確かに駄目ですね。
しかし、c++って深いですね…
>>539
今ソース探してるから、信じるのは後にしてね。
どっかで見たんだよなあ・・・・コンパイラは、private、public、protectedの
各々のデータメンバをまとめることがあるから、データメンバの並び方に
依存したプログラムを書いてはいけない、という文を。
>>541
でも本当っぽいですね…
自分も少し探してみましたが見つかりませんでした。
>>509
placement new?
544520:02/09/05 04:44
522
ありがとうございますgdbを使用して
だいたいの原因を切り分けられるようになりました。
しかし今度は実行時にsignal6エラーを吐いて失敗するようになりました。
このエラーはなんなのでしょうか?検索エンジンで調べても不思議なほど
情報が少ないですね。
別に珍しいエラーではないと思っているのですが・・
>>532のソースと>>538のソースの関係が見えません。

> fl_A a_flAとA m_Aの順序が入れ替わる
って、 a_flA はローカル変数で m_A は B のメンバですよね?
ローカル変数に public も private も関係ないし、
入れ替わるってどういうこと?
バイナリレベルでのメンバの配置が public や private の影響を
受けるというのと混同してるのでは。
>>546
指してる先は>>544じゃないのか?

というわけで>>546はポインタのミスに気を付けよう:)
549デフォルトの名無しさん:02/09/06 11:04
vector vec;
して
myClass *myclass = new myClass("test");
vec.push_back(vec);

したばあい
vec.clear()で廃棄おっけーですか?
それともdelete vec[0]が必要なのでしょうか?
これだと結局vectorの要素一つ一つを回していかないといけませんよね?
deleteが要ります。
いやならスマートポインタ使え。イジョ。
スマートポインタつっても std::auto_ptr はだめだぞ。イジョ。
552デフォルトの名無しさん:02/09/06 17:49
なんか、ここで答える人達って
「タイシタコトナイヨネ」
どういう答えが聞きたかったのですか。
たいしたことある答えが必要なら、たいしたことある質問してください。
554デフォルトの名無しさん:02/09/06 18:01
いま552はムキになって長文の質問を(しかもわざと難しく)書いている最中です。
>>549
・・・・・

え?
vector vec;

vec.push_back(vec);

557デフォルトの名無しさん:02/09/06 18:45
#include <iostream.h>#include <string.h>
struct charactor{
public:
float posX,posY;
};
class CLeft{
public:
charactor *C;
void SetP(charactor *Chara){C=Chara;}
float GetP(){return C->posX;}
};
class CRight{
public:
charactor Own;
CRight(CLeft cl,float px){Own.posX=px;cl.SetP(&Own);}
};
int main(){
CLeft cl;
CRight cr(cl,1.0f);
cout << cl.GetP() ;
return 0;
}
コンパイルは通るのですが、これを実行すると、エラーが出てしまいます。
構造体のポインタを宣言したところがまずいようなのですが、何が悪いのか
自分ではわかりません。アドバイスお願いします。
値渡しになってるよ。

CRight(CLeft& cl,float px){Own.posX=px;cl.SetP(&Own);}
        ~~
559デフォルトの名無しさん:02/09/06 19:26
無事解決しました。ありがとうございます。
しかし、なぜこの状況でアドレスで引数を宣言しないといけない理由が
わかりません。もっと精進して参ります。
>>557
プリプロセッサ命令は一行に複数書くなよ。変だよ。すごく変だよ。
>>557
値渡しだとCRightのコンストラクタを呼び出す際に、CLeft型の一時変数が
作られ、それが渡される。

そしてSetPはこの一時変数のアドレスをcharacter *Cに代入するため、コン
ストラクタの実行が終わった時点で一時変数は消去され、*Cはダングリング
ポインタとなる。

このポインタに対しGetP()を起動すれば何が起きてもおかしくない。
>>561
と思ったが、微妙に違ってた。

cl本体の*Cには何も代入されてない状態でGetPを呼び出しているのでした。
だから何が起きてもおかしくない、と言い換えます。
>>557
関係ないですが、#include <iostream>は使えないのですか?
>>557はJavaをやってたんじゃないかと推測。
565デフォルトの名無しさん:02/09/06 23:33
質問です。Visual C++6.0にて

void main()
{
ifstream ud;

ud.open("test.dat");
if(ud.bad()){
cerr<<"can't open file\n";
}
ud.close();
}

を作成・実行すると、"test.dat"なるファイルが存在しないにもかかわらず、なぜかサイズ0の
ファイル"test.dat"を勝手に作成して、 if(ud.bad()){} を素通りしてしまいます。
どうすればファイルを勝手に作らないように出来るでしょうか?
ios::nocreate
567デフォルトの名無しさん:02/09/06 23:49
>566様〜、解決しました。多謝。

ud.open("test.dat",ios::nocreate);
if(ud.fail()){…}



568デフォルトの名無しさん:02/09/06 23:54
ライブラリ等を作りたいときに、
Cでいろいろ関数を書いて、DLLにしておけば
VBなどで呼べますよね

なら、C++でクラスを用いてライブラリを書いたとき
COMを使わずにVBから呼べるDLLって作れるんですか?
569デフォルトの名無しさん:02/09/06 23:55
■10.000円の高額収入
1件につき最大10.000円の高額収入。月収100万円以上も可能。
■画期的なビジネス!
インターネットを利用したこれまでにない斬新で画期的なビジネスです。
■誰でも出来ます!
インターネットができる環境の方なら誰でも参加可能です。
インターネットを利用したビジネスですので、自宅や会社で好きなときにで
きるビジネスです。
■専門的な知識は一切不要!
ビジネスに必要なツールは全て当社で用意いたします。
また、サポートも万全です。
■詳細は今すぐこちらから
http://www.bea.hi-ho.ne.jp/paisen/
>>565
void main() 気持ち悪い
っていうか、誰がvoid main()なんて広めたんだよ…。
int main(int argc, char **argv)だろうがと小一時間(略
// int main(int argc, char **argv, char **env) ってのもあるね。
VC++的には合法だからだろ<void main()
>>572 プ
悪い習慣が何でもVCのせいだとは恐れ入った。
>main 関数および wmain 関数が void 型 (戻り値なし) を返すように宣言することもできます。
VC++6.0のヘルプから抜粋。

574 じゃないが、
>>575
それが本当に void main() と書くヤツがいる「原因」なのか?
class AA : public A;
A *a;
があって
((AA)(a[i])).foo (); はダメで
((AA*)(a))[i].foo (); はOKなのは何故でしょうか?
>((AA)(a[i])).foo ();
AからAAへの変換コンストラクタが必要

>((AA*)(a))[i].foo ();
A*からAA*にstatic_castされる。
コンパイルできるからといってOKとは限らない
579デフォルトの名無しさん:02/09/07 09:24
>571
だって、小規模なテストするには楽なんだもん…
void main(void)で教わりました。
多分ああいう教師のせいだと思います。
もちろん私はdouble main()にしていますが。
581デフォルトの名無しさん:02/09/07 09:31
>>579
void main()よりもint main()の方が短くていいじゃん。
mainのreturnは省略してもいいんだし。
582デフォルトの名無しさん:02/09/07 09:57
void main() で書いてある本があるからだろ。
void main() でもエラーでないんだし
double main()でもFILE *main()でもエラーは出ない。
VC6なら警告も出ないね(/W4)
ここはまた main() を議論するスレになったんですか?
int main()
int main(int, char **)
int main(int, char **, char **)

これら以外は main() と認められず。
586デフォルトの名無しさん:02/09/07 11:29
グローバルなクラスのインスタンスは
いつコンストラクタが呼ばれるか不定という話がありましたが

グローバルなクラスのポインタ(Class* ctest;)を用意して
mainでインスタンス生成(Class c;)→ポインタコピー(ctest = &c;)
extern Class* ctest;で別モジュールから弄ったりしたら
怒りますか?
587デフォルトの名無しさん:02/09/07 11:30
>>585
C++ではint main(int, char **, char **);も認められたのか?
>>586
「main に入った時後、最初に使う瞬間」にならどのグローバルインスタンスも
初期化されていることは保証されてように読めるので、それは
あまり意味がないのではなかろうか。

> [3.6.2]
> It is implementation-defined whether the dynamic initialization
> ...(略)... is done before the first statement of main or deferred to
> any point in time after the first statement of main but before the
> first use of a function or object defined in the same translation unit.
>>586
main以前にctestを使わなければ問題ないのでは?
でも、もしそうなら別に実体でも構わないと思うけど・・・
>>585
Embedded C++/C99ではvoidも認められてはずですが何か?
>>586
Cやその他のライブラリ関数を使わないなら問題ない
592586:02/09/07 12:35
>591
実は、初期化とか面倒なウィンドウの生成と
DirectDrawをひとまとめにしちゃって
他のモジュールからはDirectDrawオブジェクトのインスタンスしか
見えないようにしたいナァという話なのです
>>590
freestanding まで視野に入れて議論するのは無意味だろ。そもそも組み込み系
だと「終了してはいけない = main から return した瞬間にハングアップ」とか「エン
トリポイントが main じゃない」とかもアリアリだから。

hosted environment では C99 でも main は int のみ。以下、規格書から抜粋。

> 5.1.2.2.1 Program startup
> 1 The function called at program startup is named main. The implementation declares no
> prototype for this function. It shall be defined with a return type of int and with no
> parameters:
>
>  int main(void) { /* ... */ }
>
> or with two parameters (referred to here as argc and argv, though any names may be
> used, as they are local to the function in which they are declared):
>
>  int main(int argc, char *argv[]) { /* ... */ }
>
> or equivalent; or in some other implementation-defined manner.
594デフォルトの名無しさん:02/09/07 15:02
>>593
組み込み系まで視野に入れて議論するのは無意味だろ。
595593:02/09/07 15:50
>>594
俺に言うなよ。void main() が OK っつーのは freestanding の話で、即ち
組み込みなんかも視野に入れての意見なんだから >>590 に言ってくれ。
っていうか大人しくint main()にしろよ。voidからintに改めるのがそんなに面倒なコトか?
無難な方法を使うってことができないのか?
597デフォルトの名無しさん:02/09/07 16:48
俺は自分のスタイルを貫き通す。これがポリシー。
自分を捨てたプログラミングなんて、やってらんない。
だから俺はいつでも void main(void)。
没個性プログラマーは、社会の歯車になって埋もれてしまえばいいよ。
なんでも個性と呼ぶのは問題だろ、現実を見ろ…とネタにレス。
>>597
創造性がない奴に限って、どうでも良いところで差別化を図りたがる(w
なるほど。だから>>597には仕事が来ないのですね。
601デフォルトの名無しさん:02/09/07 17:30
>>597
単なる独りよがり。別名ワガママ。
602デフォルトの名無しさん:02/09/07 17:31
来月のUNIX Magazineの特集は「個性派プログラミングで差をつけよう!」
らしいよ。注目だね。
>>597
そろそろ「釣れた」と書いて逃げる頃合でしょうか?(^^)
604デフォルトの名無しさん:02/09/07 19:02
すみません。
マイクロソフトのC++でアプリの作製方法等を詳しく解説した
HPありませんか?
なかなか見つからないので、お願いいたします。
猫でもわかる
606577:02/09/07 19:42
>>578
勉強して出なおしてきますありがとう
607597:02/09/07 21:30
釣れすぎワラワラ
http://pc3.2ch.net/test/read.cgi/tech/1030606700/594
仕方なしにマルチしますすいません。
あっちでは間違っているといわれたけど、どのあたりがおかしいんでしょうか?
間違っているとは思えないんだが、
オブジェクトの作成ではなくオブジェクト用のメモリ確保と初期化って事か?
610608:02/09/07 22:30
ありがとうあなたは良い人です。(@@)うるうる(感動している)
>>608
あってるから安心しろ。強いて言えば>>609だが。
612608:02/09/07 22:33
安心しますた。
new演算子を使うとメモリ領域確保と同時にコンストラクタ呼び出せる
から便利だね。mallocだと明示的にコンストラクタ呼び出さないといけ
ない。
delete NULL;を必ず1ソースに1つは含める。
これが俺のPolicy!
615614:02/09/07 23:15
(-_-)
>>614
なんか意味あんの?
delete ptr; としたあと ptr = 0; とするのなら二重deleteを防ぐ意味の上で
有効なテクだろうが、delete NULL; の必要性がわからない。
>>614
::Sleep(0)(あるいは1)なら分かるけど
delete NULL
は型がわからないからコンパイル通らないと思った
620デフォルトの名無しさん:02/09/08 00:04
昨日,すれ立てるまでもない…に投稿したけど,レスがつかなかった
のでこちらに投稿させていただきます.

C++で数値計算のプログラムを書いてます.ある変数(double型)を
volatileをつけて宣言した場合と,そうしなかった場合で,計算結
果が異なってしまいました.コンパイラによる最適化が問題かと思
い,最適化しないようにオプション(-O0)をつけてコンパイルしたの
ですが,結果は変わりません.これはコンパイラのバグでしょうか?
あるいは,C++の仕様の範囲内でしょうか?コンパイラはg++を使用し
ております.
それ以前の問題でNULLは整数リテラルの0だからdeleteできないのが普通だろ。
622デフォルトの名無しさん:02/09/08 00:12
>>620
なぜvolatileをつける必要がある?
>>620
volatile をつけた時と、つけない時でどっちの結果が正しいの ?
また、マルチスレッドは使ってるの ?
NULLマクロを使うには cstddef をインクルードする必要がある。

>>620
volatileは本来の変数の値には影響しない。g++のバージョンとCPUの組
み合わせによるバグかもしれない。
625620:02/09/08 00:26
お返事ありがとうございます.

>>622

元々,同じ計算を実行する(と私が思っている)ソースが2つあるのですが
2つの計算結果が違ってしまったんですよ.いろいろ検証してみた結果,
問題の変数が,一方ではグローバル変数,もう一方ではメンバ変数になっ
ているのが原因らしいということがわかりました.で,メンバ変数の方を
volatileつけて宣言するか,定数に置きかえれば,2つの計算結果が完全
に一致したわけです.私としては,最適化の副作用かなと思って,-O0と
してみたわけですが,これは効果なしでした.

>>623

どちらが,正しい結果かはわかりません.また,マルチスレッドでは
ありません.コンパイルして,ターミナル上から 普通に(?)実行して
います.解いているのは微分方程式です.非線形項が入っているとは
いえ,同じ計算機で,みため同じソースなので,同じ計算結果が出ない
とおかしいと思うのですが.レジスタに割り当てられる際に値が変更
されることも考えにくいし,丸め方か何かが影響しているのでしょうか.
626620:02/09/08 00:32
>>624

gccの2.96とPentium3で主に実行していました.CPUのバグも
疑って,Pentium2,Pentium4で実行してみましたが,改善され
ませんでした.gccをバージョンアップした方が良いのでしょうか.
627デフォルトの名無しさん:02/09/08 00:35
風俗サイト広告逝ってよしっ!第3回戦
ただいま戦闘中!!!
嫌いな人はこちらへ漏れなく串つき

http://live.2ch.net/test/read.cgi/festival/1029826982/l30


>>626
2.96でそんなバグは聞いたことがないけどなあ。Pentium3ならなおさら
バグはないでしょう。

3.2が出ているからバージョンアップしてみるのも手です。
>>625
その違いって、誤差レベルなの ? だったら、計算順序による丸め誤差の
影響はありえる。(丸め誤差については、C++ の仕様の範囲外。)
テンプレートの一部だけ特殊化って出来ないですか?
template<class A, class B>
class C
{
 ...;
};
template<class T>
class C<int, T>
{
 ...;
};
と言う感じで
631622:02/09/08 00:44
>>620
文面から見る限りではvolatileで何かが変わるとは思えないし、コンパイラのバグもそうそうあるものじゃない。
ソースを見ないとなんともいえないけど、ステップ数はどのくらい?
どっかに上げれば暇だからみてもいいよ。
とりあえず前後のポインタ操作にバグがあったりはしないか?
633デフォルトの名無しさん:02/09/08 00:56
質問です。
VC++6.0にて配列を作るのに、一次元ならば

double *test;
test = new double[2];

delete[] test;
test=NULL;

で実現できるのですが、二次元以上になるとエラーが出てきて実現できません。
一体どのように解決すれば宜しいのでしょうか?よろしくお願いします。
>>617
ちょっと勉強になった.
635デフォルトの名無しさん:02/09/08 01:00
>>633
二次元以上は自分で確保する


char **pStr = new char[5];
pStr[0] = new char[100];
.
.
.
636620:02/09/08 01:01
>>628

ありがとうございます.試してみます.

>>629

差は時刻とともに爆発的に増大します.系の性質から,微小誤差が指数
関数的に拡大することは承知しています.ですが,表面上同じコードが
volatileをつけるかつけないかで,違う結果を出すといったことがある
と,コンパイラのちょっとしたさじ加減で,異なる計算結果が得られて
しまうかも〜と不安になりまして.

計算順序はソースレベルでは同一です.丸め誤差がC++の仕様の範囲外
ということは,丸めに関しては,コンパイラあるいはCPUに依存すると
いうことでしょうか.
俺にはC++という素晴らしい彼女がいるのに・・・
体が満たされないってこういうことを言うのね(涙
>>636
> 計算順序はソースレベルでは同一です.

かなり注意深く書いてないと、ソースレベルで計算順序なんてわからない
ぞ。

> 丸めに関しては,コンパイラあるいはCPUに依存するということでしょ
> うか.

あたり。

とりあえず、gcc なら long double とかが使えるらしいので、試してみ
たら ?
639デフォルトの名無しさん:02/09/08 01:13
>>635
レス有難う御座います。が、やはりできません。

double **test = new double[i];
はもちろんのこと
double **test = new *double[i];

もエラーで弾かれてしまいます…
double** p = new double*[i];
これだと少なくとも誤差は出ないね。g++2.96 + Pen3

#include <fstream>

int main()
{
double d = 1.000001, dd = d;
volatile double e = 1.000001, ee = e;

std::ofstream of("test.txt");

for (int i = 0; i < 1000000; i++) {
of << d << ' ' << e << ' ' << d - e << std::endl;
d *= dd;
e *= ee;
}
}
642デフォルトの名無しさん:02/09/08 01:23
>640
おおおぉ〜!いけました。哀れな初心者に親切なご指導を有難う御座いました!
643620:02/09/08 01:33
>>622

ありがとうございます.ですが,ソースは,見せると素性がばれ
ますのでお見せできませんm(__)m.ステップ数というのは「ステ
ップ」の意味を存知ませんので,いくつかわかりませんが,ソース
の中では,微分方程式を解く際の刻み幅500個分の計算を行っています.
250個めまでは,ほぼ一致しますが,以後は全く解の軌跡が異なります.

お返事頂いた皆様に感謝します(わざわざプログラムまで書いて頂きまして).

皆様のお返事を見ていると,問題は,丸め誤差であって,volatileをつ
けて計算結果が一致したのは,副次的な作用に過ぎないようですね.
そもそも,このような計算が,私の目的に沿って必要なことかどうかと
いうこと自体を,改めて考えなおす必要もありそうです.

というわけで,今日は(勝手ながら)ここらで収束させて頂きます.
また,何かありましたら,お願いいたします.
>>643
ステップ数はおおざっぱに言えば、ソースプログラムの行数のこと
微分方程式を解くというと、パッと思いつくのはオイラー法かルンゲ・クッタ法
だなあ。特に難しい事はしてなかったように思うんだけど。
>>636
俺ならアセンブラコードを出力させて、差を追ってみるけどな。
-Sオプションを付けてコンパイルしみたけど、何やら面妖なソースを
吐き出しました。

movl%ebx, -320(%ebp)
movl%esi, -316(%ebp)
fldl-320(%ebp)
movl-300(%ebp), %eax
addl$16, %esp
fmullLC0
incl%eax
movl%eax, -300(%ebp)
fstpl-320(%ebp)
fldl-32(%ebp)
fldl-40(%ebp)
movl-320(%ebp), %ebx
movl-316(%ebp), %esi
fmulp%st, %st(1)
fstpl-32(%ebp)
jmpL42
>>613
C++には、デストラクタの呼び出し方法は存在するけど、コンストラクタのそれは存在しないだろ
これがnon-volatileの計算部分

movl%ebx, -304(%ebp)
movl%esi, -300(%ebp)
fldl-304(%ebp)
movl-284(%ebp), %eax
addl$16, %esp
fmullLC0
incl%eax
movl%eax, -284(%ebp)
fstpl-304(%ebp)
movl-304(%ebp), %ebx
movl-300(%ebp), %esi

そしてこちらがvolatileの計算部分です

fldl-32(%ebp)
fldl-40(%ebp)
addl$16, %esp
incl%ebx
fmulp%st, %st(1)
fstpl-32(%ebp)
jmpL42

volatileと指定すると一度FPUにデータを読みとった後mulを実行している
ように見えます。
ちなみにLC0というのは定数データとしてコンパイルされています。

LC0:
.long208632331
.long1072693249

volatileではこのような不変の値をも変数として扱うようにするようです。
>>648
確かにそうですね。やるとすればコンストラクタと同じ中身を持つ関数を
定義しておいて、それを後から呼び出すしかないですね。
mallocのポインタnewにわたせば?
>>648
new( p ) T( ... );
placepent newを使うのか・・・・トリッキーだ・・・
>618
naru
>>648 コンストラクタの明示的な呼び出し方はあるだろ。
A* a;
a->A::A();
>>630
C++標準ならできるが、Visual C++ならできない。
この場合はインナークラスで代用することはできる。はず(笑)
template<class A, class B>
class C
{
 template <typename T> class sub {
 public:
  B func(T a) { ... }
  ...;
 };
 template<> class sub<int> {
 public:
  B func(int a) { ... }
  ...;
 };
 sub<A> impl;
public:
 B func(A a) { return impl.func(a); }
};
658630:02/09/08 10:04
>>657
そうですか…
無名の共用体とか引数の違うコンストラクタがあるんで
インナークラスでは回避できなさそうです。
どうもありがとうございました。
659630:02/09/08 10:41
すいません。その方法で回避できそうです。
感謝感激です。
>656
何これ。
動かんぞ。

#include <iostream>
#include <cstdlib>
#include <cstring>

class A {
char* ptr;
public:
explicit A(char* str) { ptr = static_cast<char *>(std::malloc(strlen(str) + 1)); }
operator char*() const { return ptr; }
~A() { std::free(ptr); }
};

int main()
{
A* ap = static_cast<A*>(std::malloc(sizeof(A)));
ap->A("string");
std::cout << *ap << std::endl;
ap->~A();
free(ap);
}
662デフォルトの名無しさん:02/09/08 11:51
ap->A("string")って何?
new(ap)("string")だろ。
VC6で動いたよ
#include <iostream>
#include <cstdlib>
#include <cstring>

class A {
char* ptr;
public:
explicit A(char* str)
{
ptr = static_cast<char *>(malloc(strlen(str) + 1));
strcpy( ptr, str );
}
const char* c_str() const { return ptr; }
~A() { free(ptr); }
};

int main()
{
A* ap = static_cast<A*>(malloc(sizeof(A)));
ap->A::A("string");
std::cout << ap->c_str() << std::endl;
ap->A::~A();
free(ap);

return 0;
}

つーか、素直にoperator new オーバーロードしようぜ
おっと、new(ap)A("string")ね。
>>649-650

コンパイラが volatile を正しく処理しているようにしか見えないが
>>636
殆どの CPU では、処理のわずかな違いで計算結果が変わってしまう。
なお、大抵のコンパイラでは、計算精度を一定に保つオプションがある。
内部表現のbit数とメモリにストアしたときのbit数の違いかもしれないと
疑ったけど、-O0すると必ずメモリにストアするから違うねえ・・・
>>667
x87 って、確か浮動小数点レジスタの精度は 80bit (double の 64bit より長い)
あったよね。

64bit の即値とかけ算する fmull と、80bit レジスタ動詞でかけざんする fmulp
で精度に狂いが出てるんじゃないの?
ロードするときは64bitだからそれはないと思う
それから-O0やvolatileだったら、計算するたびにメモリにストアするから
その都度64bitになってる筈
>>656
ダウト

ANSI C++ の規格書から抜粋。
> 12.1 Constructors
> 1 Constructors do not have names. ...
> 2 ... Because constructors do not have names, they are never found during name lookup; ...

クラス A のコンストラクタは A() という名前では呼べません。
素直にnewインクルードしてplacement new使えよ…

嫌ならこういう関数でも書くか?
template< typenameT >
inline T* CallConstructor(T& instance)
{ return new( &instance ) T; }
>>671
Factory だな、そりゃ。
>>671
instance を最初期化であぼーんだな、そりゃ。
674デフォルトの名無しさん:02/09/08 22:35
テンプレートの引数に型ではなく値を指定する事ってできないのでしょうか?
下記のような事がしたいです。(擬似コード)

template<class T, const_value V>
class hoge
{
public:
static T s = V;
static T getClassValue()
{
return s;
}
};

よろしくお願いします。
>>674
テンプレにしなくても、コンストラクタにでも渡すようにしたら?
>>674
intなら渡せるはず。
>>674
template<class T, T V> でどう?
T にclass型は渡せないけど。
渡せるのは、組み込み型ならいけるんだったかのぅ。
ポインタ型のときはその値は外部リンケージが要る。
678デフォルトの名無しさん:02/09/08 22:55
あるクラス A について、

A a = 初期値;



A a(初期値);

って同じ物だと思っていましたが、もしかして動作がちがうのですか?
679674:02/09/08 23:09
>>675-677
みなさんレスありがとうございます。
実は渡したいのは関数ポインタ、それもメンバ関数ポインタなのです。
「プロパティ」みたいなテンプレートクラスを作りたいのですが…。
>>678
explicitを付けてコンストラクタを定義すると、前者の形は使えなくなる。
681674:02/09/08 23:21
さらに追加で質問です。
現在は >>675 さんの案のようにコンストラクタで渡す方式(動的バインド)で
試しているのですがこれも現状うまくいっていません。

クラスの宣言の中では、そのクラス名ってテンプレート引数に渡せないのでしょうか?
VC6 だと
  error C2027: 認識できない型 'ClassName' が使われています。
のようなエラーが出てしまいます。
下記は試している途中のコードです。
template <class Subject, class MemberFunc> class MemberFuncCaller
{
private: Subject& subject_;
private: MemberFunc operation_;

public: MemberFuncCaller(Subject& subject, MemberFunc operation)
: subject_(subject), operation_(operation){}

public: void Do(){ (subject_.*operation_)(); }
};

class User
{
typedef void (User:: *UserFunc)();

public: inline void MemFunc(){ printf("Do it, ok!\n"); }
// ここでコンパイルエラー
MemberFuncCaller<User, User::UserFunc> DoObject(user, &User::MemFunc);
};
解決策をご存知の方よろしくおねがいします。
682678:02/09/08 23:23
>>680
なるほど。ということは、前者は

A a(なにか);
a = 初期値;

と同じになるわけですか?
>>679
こんな感じか?bcc5なら通った。
あと、VC6でtemplateを使いまくるのはかなりキッツイので覚悟した方がいいぞ。

template
<
  typename Value,
  typename Class,
  Value (Class::*Getter)(),
  void (Class::*Setter)(Value)
>
class property { ... };

//property<std::string, SomeClass, &getName, &setName> name;
>>682
その通り。

>A a = 初期値;
コピーコンストタクタが呼ばれる

>A a(初期値);
直接初期化 A::A(初期値)が呼ばれる

ただし、RVOによりコピーコンストラクタは省略されることもある。
explicitは初期値がA型なら問題ない筈
こういうことかな。

#include <iostream>

class A {
int x;
public:
explicit A(int i) { x = i; }
void print() const { std::cout << x << std::endl; }
};

int main()
{
A a(1);
//A b = 2; //エラー
A b = A(2);

a.print();
b.print();
}
686678:02/09/08 23:31
>>684
なるほど。ありがとうございます。
要するに、両者は違うものだが、最適化で同じになりうる、という認識で。

>>674
なんか割り込んでたみたいですみませんでした
>>679,>>683
プロパティということは、メンバ関数をオーバーロード
している?
たしか、多重定義されているメンバ関数のポインタは、
テンプレートの引数として使えないはず。
688674:02/09/08 23:57
>>683
VC6 だと property のインスタンスの宣言時に「特殊化」のエラーが出ます。
メンバ関数へのポインタから通常の関数へのポインタへの変換ができない
という内容みたいです。
特殊化も、メンバ関数ポインタから通常の関数ポインタへの変換もしてないのですが…。

>>687
いえ、メンバ関数は一個です。


現状の悩みは >>681 でも書きましたが、
このクラスを利用したいはずの、利用側クラスの内部に宣言が書けない事です。
相変わらず 認識できない型 'ClassName' が使われています が出てしまいます。
689674:02/09/09 00:06
ひとつ勘違いしてました。
メンバ関数ポインタから関数ポインタへの変換ができないというエラーは出ません。
でるのは
error C2973: 'property' : テンプレートの仮引数 'Getter' が無効です。
でした。

さっきのエラーは Value (Class::*Getter)() を書き間違えて
Value (*Getter)()
とした為にでていました。
690bloom:02/09/09 00:14
>>681
> // ここでコンパイルエラー
> MemberFuncCaller<User, User::UserFunc> DoObject(user, &User::MemFunc);
これって typo?
MemberFuncCaller<User, User::UserFunc> DoObject(User, User::UserFunc);
ではなくて?
692683:02/09/09 00:26
>>681
ちゅーかよく見たらあーた、クラス定義の中で
コンストラクタは呼び出せないよ、そりゃ。

× MemberFuncCaller<User, User::UserFunc> DoObject(user, &User::MemFunc);

○ MemberFuncCaller<User, UserFunc> DoObject;
○ User() : DoObject(*this, &User::MemFunc) {}
693620:02/09/09 00:40
昨夜はどうもありがとうございました.解決策が2つみつかりました.

>>668 などで指摘されている通り,double型(64ビット)の変数がレジスタ
(80ビット)に割り当てられた際に,余分な桁がまぎれこみ,計算結果に
違いが出たようです.

私が思いついたのは次の2つで,結局,2を選択しました.

1. g++のコンパイルの際に-ffloat-storeオプションをつける.
これにより,double型(64ビット)変数のレジスタ(80ビット)への割り
当てを抑制できました.

2. double型の変数をlong double型で宣言しなおす.
もともとlong double型は80ビットですので,レジスタに割り当てても
  不要な桁が入りこまないようになります.

ちなみに,計算速度は,1,2で,大きな差はありませんでした.
694674:02/09/09 00:45
>>691
???? テンプレートじゃない普通の引数に型名ですか?よくわかりません。
>>692
しまった。この間仕事で Java とか使ってたので宣言時に初期化できるような気になってました。
これを適切に直しても VC6 だと利用側のクラス名を判別できないエラーが出ます。

bcc ならできるとの事なので、いまインストールしてみたのですが、たしかにコンパイルできますね。

ところで、この場合、Getter と Setter はどうやって使えばいいのでしょうか?
template <typename Type, class ClassName, Type (ClassName::*Getter)(), Type (ClassName::*Setter)(Type)>
class property
{
private: Type m_Value;
public: ClassName x;
public: Type& operator= (const Type& rhs){ return (x.*Setter)(rhs); }
public: operator Type() { return (x.*Getter)(); }
};
class User
{
private: int v_;
public: int Get(){ return v_; }
public: int Set(int v){ v_ = v; }
property<int, User, &User::Get, &User::Set> ValueProperty;
public: User() : ValueProperty(){}

};
としてmainとかで
User user;
user.ValueProperty = 50;
printf("%d", user.ValueProperty);
こうすると、未定義の構造体 'User' というエラーが出てしまいます。
なぜでしょうか?
>>693
うーん、そうだとしても、-O0で、volatileとそうでないものに違いがでる
というのは納得行かんなあ・・・

まあ解決して何よりなんだけど・・・
>>692,>>694
DoObject(…) ってのはメンバ変数定義(のつもり)かよ…。関数宣言かと思った。
697674:02/09/09 01:09
>>696
よく Java や C# とごっちゃになるんです。
まんま Java/C# 式のまちがいをした時は
「へんてこな純粋仮想関数の宣言です!」とか怒られるんですよ。

今日はもう寝ます。みなさんありがとうございました。
質問者が寝てしまっても、次にきた時の参考になるように
アドバイスを残してくださる優しい方がいた時のためにあらかじめ
書いておきます。

ありがとうございます!
698デフォルトの名無しさん:02/09/09 01:24
どうでもよさげな話で恐縮だが、クラスの中身ってpublicから書く?
それともprivateから書く?
どうでもよすぎ。
見た目効率〜とかいうスレがあったと思うからそっち逝け。
>>698
public -> protected -> private

全部pからはじまるのがむかつく。・・・・なんとなく。
>>698
public フィールド
protected フィールド
private フィールド
public メソッド
protected メソッド
private メソッド
>>699
すまぬ。

>>700
今、僕もそうしています

>>701
フィールドとメソッドで分けるの?


結構、private (先頭無指定)から 書いてあるソースを見かけることが多いので、
ほかの人はどうしているのかと思い、質問してしまいました。おじゃましました。
703620:02/09/09 03:05
>>695

確かに,-O0で最適化を抑制しているのにvolatileの有無で結果が違
うのは,変数がレジスタに割りつけられている可能性が出てきておか
しいと思います.もう少し検証して何か出たら,また報告します.
>702
そりゃスコープ省略すると勝手にprivateになるからだろw
705701 ◆k/Ubp.Kg :02/09/09 06:27
>>702
分ける。理由は特にない(藁。つか、フィールドとメソッドが一緒だと読みにくいのよね、俺的に。
まぁ趣味だから、どう書くかよりも統一されてるコトの方が重要だと思ってる。

>>704
そうだね。俺、あれが好きじゃないからpublicを頭に回してprivateを明示的に書くようにしてまふ。
これもやっぱし趣味だな。
706704:02/09/09 06:31
ちなみに漏れはオブジェクト指向(データ指向)マンセーなので
利用者がスグに知りたいパブリックメンバを前に、
プライベートなメンバは後ろ〜の方に書いてます

そもそも外から見られたく(いじられたく)なくてプライベートにしてるのに
真っ先に書いてあるのは不自然じゃないか、と
707683:02/09/09 08:14
>>694
> public: ClassName x;
これだとUserの中にproperty<..User..>の中にUserの中にproperty<..User..の中に…
の無限入れ子になってしまう。C++はJavaじゃないので参照なりポインタなりは
そのむねちゃんと書かんといかんよ。

template <typename Type, class ClassName, Type (ClassName::*Getter)(), void (ClassName::*Setter)(Type)>
class property
{
private: Type m_Value;
public: ClassName& x;
public: property& operator= (Type rhs){ (x.*Setter)(rhs); return *this; }
public: operator Type() { return (x.*Getter)(); }
public: property(ClassName& owner) :x(owner){}
};

class User
{
private: int v_;
public: int Get(){ return v_; }
public: void Set(int v){ v_ = v; }
property<int, User, &User::Get, &User::Set> ValueProperty;
public: User() : ValueProperty(*this){}
};
708683:02/09/09 08:16
> private: Type m_Value;
あとこれは要らんな。
個人的に値とpropertyを分けるのは好きじゃないな

property < int, ...> Value;

Constructor() : Value(this, 初期値) {}

Get(int& value);
Set(int& value, int& new_value);
710デフォルトの名無しさん:02/09/09 21:45
ファイルを操作するクラス CFileがあります。
ファイルのパスを格納しているクラス CFilePathがあります。
パスにならってファイルを開く関数 CFilepath::open() を定義して、
CFileをなんらかの形で返したいのですが、どのように返したらいいのでしょうか?

最近CからC++に移ってきたんですが、Cみたいにポインタで返さなくても
メモリの大量コピーとかはおこらないんでしょうか?
CFilePathって一般的にはやや無理筋そうなクラスに見えるけど、
なんのためにあるの?
むしろ、CFile に getpath() みたいなメンバの方が自然な気が。
あと、

>最近CからC++に移ってきたんですが、Cみたいにポインタで返さなくても
>メモリの大量コピーとかはおこらないんでしょうか?

戻り値の話なら、値で戻せばコピーが起きるのは CもC++も同じ。

てーか、そもそも、Cで何らかのオーバヘッドが発生する局面で、
C++だとそれが起きないなんて状況は、まずないね、逆はよくあるけど。
713710:02/09/09 22:45
どうも書き方が悪かったようです。ここのパスってのは検索パスです。
CFilePathのコンストラクタで
{"/usr/share/hoge","/usr/local/share/hoge"}みたいなのが読み込まれて、
CFilePath.open("fuga.dat")
で/usr/share/hoge/fuga.dat,/usr/local/share/hoge/fuga.datの順に存在した物を開くと
いうものを作成したいのです。
>>713
CFile を継承して、コンストラクタと open() を定義すれば良いと思うが...。
715710:02/09/09 23:23
>>714
そうすると、ファイルを開くたびに検索パスを読み込む方法しか思い浮かばないのです。
C++まだよくわかってないんですが、、
>>715
毎回読む、グローバルに保存しておく、staticメンバに保存しておく、お好きなように。
717710:02/09/10 00:52
毎回読む、グローバルに保存は避けたいですね。
staticメンバってのはわからないので、調べてみます。

あと、一応、クラスを返すときはどういうように返すのが一般的かを
教えてください。
718674:02/09/10 01:23
やっぱり先にお礼を書いておいて良かった!

>>707
そういえばそうでした、ありがとうございます。
ところで、このプロパティの中身をオブジェクトにして

int val = someObject.Property.memberVariable;

のように書いたときに、 someObject が int に変換できないという趣旨の
エラーが起こるのですが、この時は何が起こっているのでしょうか?
冷静に考えると、プロパティの実体のメンバにアクセスするための
ドット演算子が未定義である為に起こる症状な気がするのですが、
operator. ってオーバーロード出来ないんでしたでしょうか?

こういう場合に自然な振る舞い(C#などのプロパティのような振る舞い)に
する方法は何かありますか?
どなたかよろしくお願いします。

>>709
分けないと、アクセス制限の線引きが曖昧になりませんか?
インスタンスのプロパティなのに、そのインスタンスが受けるアクセス制限が
外と同じというのはちょっと…と思うのですが。
>>718
. :: .* ?はオーバーロードできん。
>>717
CFileに参照回数計測を実装すれば、ポインタ1つのコピー+αくらいで逝けるヨン。
他の場面で多少のオーバーヘッドは出るけど、
CFileみたいなクラスはそんなに速度は要求されないだろうしネ。
721720:02/09/10 02:54
って、よくみたら、staticメンバわからんとか逝ってるし。
staticメンバわからんやつに参照回数計測はまだ無理かな。
>>711
もしくは CFile::open(const CFilePath&) を作るか。
>>721

staticメンバだと、pathリストパターンjが複数存在する場合に困るような...
今回の場合、複数ないかも知れんけどね。
724683:02/09/10 07:57
プロパティって、対応する実体が無くてもあたかも存在するかのように見せられる
property<int, OwnerClass, &OwnerClass::GetLength, _> length;
int OwnerClass::GetLength() const {
 return strlen( m_string_data );
}
のが便利なとこだと思ってるので、常にメンバ変数とペアになってる
ことを仮定したpropertyテンプレートって好かんのだが…。

>>718
class property [with T=SomeValue&] {
 T operator()() const { return (x.*Get)(); }
};
と謎の()を定義して、その時だけプロパティらしからぬ
int val = someObject.Property().memberVariable;
で使うか、operator. の代わりに operator-> のオーバーロードで
我慢するしかないような気がする。
725デフォルトの名無しさん:02/09/10 09:23
オペレーターを定義するときには、
メンバー関数にするのとフレンド関数にするのとどちらが良いのでしょうか?

それぞれのメリット・デメリットにはどんなことがあるのでしょうか?

いろんな立場からのご意見をお聞かせ下さい。
スレ違いかもしれませんが、統一スレのようなので、質問させてください。

みなさんはC++を使う場合のGUIまわりはどうしてます?
Winだと、BCBかMFCというところでしょうか?
.NETの方がきれいなGUIになっていったらどうします?
727デフォルトの名無しさん:02/09/10 10:56
凄い初歩的な質問で申し訳ないんですが、よろしくお願いします。

Win32コンソール用アプリケーションで、ユーザに1ラインに複数の言葉を入れてもらい、
それを個々のstringとして認識するにはどうしたらいいのでしょうか?
例としては、ユーザがcinに
"apple banana orange grape"
と入力した場合に、スペースを認識して"apple"というstring、"banana"というstring、
という具合に個別のstringに分けたいのです。

cin >> a >> b >> c; という様な手を使おうと思ったのですが、ユーザが入力する言葉の数は一定してないので、
言葉が3つ以下の時にキチンと作動しません。

お願いします。
728727:02/09/10 10:57
すみません、上げてしまいました。;
一度に1lineまるまる拾ってきた後、それを解析
strtok()などのループ
>>727
配列も使えよ。
731727:02/09/10 11:19
googleでstrtok検索したらなんとなくわかりました。
ありがとうございます。m(_ _)m
ただし、strtok は少し癖があるから、気をつけて。
場合によっては、strtok_r を使うこと。
>>725
それは、すでに語られ尽くしてる気がするな…。
734734:02/09/10 12:40
STLの初心者ですが、教えていただきたいのですが、
過去ログの
(http://pc.2ch.net/tech/kako/1009/10090/1009071535.html)
265番目あたりの対処方法は、皆さんなら、どのように
しますか?
VC++,BulderC++で作成したsetをGNU g++でも動作させようと
しているのですが、iteratorがconstなので、エラーになります。
やはり、erase,insertをするしかないのでしょうか?
735 ◆k/Ubp.Kg :02/09/10 12:47
>>734
gcc-3.2を使わない。2.95.x使うの止めた方がイイよ。
>>725
立場がどうの、っつーほどのもんではない。
2項オペレータの左項に当該クラス以外のオブジェクトが来る場合を
許容しようとしたら、必然的に非メンバ関数として定義してやる
しかない、というだけの話。
>>727
せっかく std::string をつかってるなら、文字列を char配列にコピー
してからでないと使えない strtok よりも、string のメソッドになってる
find、find_first_not_of、substr あたりを組み合わせて使ったほうが
よいんでは。
738 ◆k/Ubp.Kg :02/09/10 13:32
boost::tokenizerは?
739デフォルトの名無しさん:02/09/10 16:18
VC++6っす。
プログラムに埋め込んで使えるようなデータベースライブラリーって
ないですか?Oracleとかだと、別途インストールしたりサーバの設定とか
面倒なので。

今まではSTLのmapとvector使ってやってたんだけど、そろそろ面倒で限界。鬱になる。

>>739
探す暇があったら自分でつくれよ低能。
741デフォルトの名無しさん:02/09/10 16:37
>>740
煽る暇があったら働けよ低能。
743デフォルトの名無しさん:02/09/10 16:45
そして
>>740=>>742という罠
744デフォルトの名無しさん:02/09/10 16:46
しかも
>>741=>>743という罠
>>739
VC++スレできけばぁ?
746 ◆JAPH9PWA :02/09/10 16:48
>>739
SQLiteはどうよ
Perlからしか使ったこと無いけど
http://www.hwaci.com/sw/sqlite/
747デフォルトの名無しさん:02/09/10 17:01
>>739
ちょいと弄れば使えると思う(BCC5.5用だが)
http://www.fuel.co.jp/~bull/odbc/

748デフォルトの名無しさん:02/09/10 17:02
>>745
べつにいんじゃない?
>>739
DAOとかのMFCにあるやつ
電子メール アドレス :
[email protected]
ジャンジャンメールクレーーーーなんでもOK!!



>>746
それ、パフォーマンス悪い
>>739
目的を明確に。

データベースといってもいろいろなんだが、何をしたいんだ? リレーショナル
データベースを使いたいのか、オブジェクトのシリアライズをしたいだけなのか、
そのあたりを詰めると話がまったく違ってくる。
C++ のオブジェクトのシリアライズをやってくれるような
データベースなんてあるの?
754デフォルトの名無しさん:02/09/11 00:29
例えば array< T > みたいなテンプレートがあって、これを容易に vector や
list に差し替える方法ってある?

イメージ的には template <class T> typedef std::vector array;
みたいな。
>>753
あるらしい。昔、エピステーメーが書いてた本で読んだ覚えがある。
(その本、捨てちゃったけど)

>>754
明らかにムダなので、ないと思われ。
template< template<class> class Container, class T > … Container<T>
757755:02/09/11 00:56
>>755
vector と list 差し替えるって話はムダだが、template を typedef したいっつー
のはあり得る話か。

ちなみに、それは無い。ただし template パラメタに template を渡す、たとえば

template <template <typename T> class Prod>
class Order {
  Prod<int> prod_;
...
};

みたいな書き方は出来るから、目的は達成できると思う。
>>757
g++ とかなら、
template< template<class> class C, class T > void foo( const C<T>& array ) {
for ( typename C<T>::const_iterator i = array.begin(); i != array.end(); ++i ) {
cout << *i << endl;
}
}

vector<int> v;
foo(v);
list<float> l;
foo(l);

みたいな書き方はできるけど。
>>758
template template parameter ね。ただ typedef template は、なぜか ANSI C++
の規格には存在しない。

(次期 ANSI C++ の規格に入る最右翼だとは思うけど)
>>753
そういうのをOODBという。
objectstore?
762739:02/09/11 10:22
いろいろなレスを頂きありがとうございます。

シリアライズできるデータベースがあるなんて知りませんでした。
今回探しているものは、リレーショナルのほうですが
そちらにも興味があります。
よろしければ名前など教えてください。
763一週間ぶり:02/09/11 12:01
こんにちわ。
enumのシンボル(?)って全部大文字じゃマクロと被って紛らわしいすかね?
enum { AHYA, UHYA }; みたいなの...
>>764
個人的には大文字を打つのがめんどくさい
>>764
定数であることを明記するため、俺は大文字にしてるけどな。

#define AHYA 0

これと enum { AHYA = 0 }; は同じようなもんだろ?

>>764
良いエディタを使え。
typedef templatesの代わりに#defineで何とかするとどれくらい残念?
768デフォルトの名無しさん:02/09/12 00:34
age
>>766
エディタで解決できる問題か?
>>767
引き篭もりが首吊るくらい残念。。。
>>727
おそレスだがstrstremとか使っちゃダメなのかい?
772771:02/09/12 01:17
作ってみた。
string s("apple banana orange grape");
istrstream ss(s.c_str());
string tmp;
while (ss >> tmp) {
cout << "data = " << tmp << endl;
}
#define AHO 0

enum { AHO=0 };

が同じなんですね。
774デフォルトの名無しさん:02/09/12 01:47
クラスのプライベートなメンバ変数を返すパブリックな関数で

int GetValue() { return a; }



const int& GetValue() { return a; }

って同じ事ですか?
肥大化しちゃった(std::vectorとかの)オブジェクトを参照したい時に
下の方が良いかなーとか思ったのですが、実際の所どうなんでしょう?
上のやり方だとオブジェクトの実体をまるごとコピーしてるように思えるんですけど
認識間違っていますか?
>>774 間違ってない。以上。
776774:02/09/12 02:17
>775
なるほどありがとうございます

ということは、追加で質問なのですが

class cA {
public:
  const std::string& GetSTR() { return str; }
private:
  std::string str;
}

int main() {
  cA a;
  std::string b;
  b = a.GetSTR();
  b.append("test");
  return 0;
}

というのは安全なコードでしょうか?
777774:02/09/12 02:18
あー・・・コンストラクタ書いて無いとかいうのは別として・・・
>>776
b = a.GetSTR();
でbにコピーされるんじゃ?ちなみに、
a.GetSTR().append("test");
は通らない(はず)。
>>778
コピーされなきゃまずいだろ。
constにはappendできないのだから。
780774:02/09/12 02:50
あれ・・・
std::string* b;
b = a.GetSTR();
b->append("test");
かな・・・

すみません、混乱してます
>>776
GetSTR()はconstであるべきだが、それ以外は別にいいんじゃないの。
782774:02/09/12 02:51
あーごめんなさい
appendじゃなくて、例えばfindとかの話でした。
プライベートに持ってるstd::mapのキーを
std::setに列挙して返すような場合です。
>>782
それなら、直に〜.find(a.GetSTR())してもいいし、
const std::string& b = a.GetSTR();
〜.find (b)
としてもいい。
何か混乱してません?>>774
落ち着いて考えてみそ。
785774:02/09/12 03:25
上手く伝わっていなかったようです
修正版コード

class cA {
public:
  const std::map<string, int>& GetMap() { return mymap; }
private:
  std::map<string, int> mymap;
}

int main() {
  cA a;
  const map<string, int>& b;
  b = a.GetMap();
  if (b.find("test"))
    cout << "OK" << endl;
  return 0;
}

こんな感じです
>783氏からちょっとヒントを得ました


が、ここまで書いてふと気が付いたんですが
こんな実装必要ないみたいでした・・・
長々と失礼しました
  const map<string, int>& b;
  b = a.GetMap();

これは許されないぞ
787774:02/09/12 03:39
あ、はい。わかります。
ごめんなさい。
>>773
(´-`)。o ( ……これだけを見ると、ぜんぜん違うと突っ込みたくなるなぁ……)
789デフォルトの名無しさん:02/09/12 11:12
>>786
これって、constじゃなきゃいいの?
「&」ってやってるのがまずい?

漏れならcAのメンバ関数にint find(string )って入れて済ますけど
嫉妬期待。
>>789
参照は宣言時に初期化されなければならない。
791デフォルトの名無しさん:02/09/12 12:45
コンストラクタ中で、外部の関数に this を 渡すとまずいですか?
コンストラクタから出る前に、問題の関数がthisの先を見ないなら
問題は無い。例えば
class Bar;
class Foo {
    Bar *m_ptr;
public:
    explicit Foo(Bar *ptr) : m_ptr(ptr) {}
};

class Bar {
    Foo m_foo;
public:
    Bar() : m_foo(this) {},
};
はOKだけど、Foo(Bar *)がptr->xxを含んでいたらアウト。
ただし、Barの基底クラスの非仮想関数を呼ぶ場合は、少なくとも普通の
処理系なら正常に動くはず。
>>792
レスありがとう。
ルール上はアウトなんですね。
794デフォルトの名無しさん:02/09/12 13:48
便乗
VC6だと
警告 Bar() : m_foo(this) {}
OK Bar() { m_foo = this;}
となるんですが、上の書き方は言語規約上OKなのでしょうか。

auto_ptr<Foo>とかで、オーナーポインタ渡すだけの為に
auto_ptrのディフォルトコンストラクタが走るのは気持ち悪いっす。
どんな警告?
796794:02/09/12 15:01
>>795
warning C4355: 'this' : ベース メンバ初期化リストで使用されました。
非静的メンバ関数の中でのみ有効な this ポインタが基本クラスの
初期化リストで使用されました。
Microsoft の拡張機能を有効にするオプション (/Ze) を付けて
コンパイルした場合はレベル 1、それ以外ではレベル 4 の警告となります。

よく考えたら、この構文通らないと、オブジェクトを直持ちした場合
構築できないじゃん。
そんなんでいいのか C++
だから、コンストラクタ内で渡した先が
そのthisの中身にアクセスしなければ合法だって言ってるじゃん
あぶない使い方になる可能性もあるから警告出たって良いんじゃない?
というか、直持ちした上で他のオブジェクトに依存するような設計が悪い。
すいません、お尋ねします。
浮動小数点数のscientific表記(0.02e+12とか)が何を意味しているか
わかりません。解説ページご存知でしたら教えてください。
800800get:02/09/12 16:19
>0.02e+12
ワラタ
801デフォルトの名無しさん:02/09/12 16:25
基本的には、ものすご〜く大きな数か、ものすご〜く小さな数を表していると思われ。
802799:02/09/12 16:36
>>800
Σ(゚Д゚;)
・゚・(ノД`)・゚・イッショウケンメイカイタノニ

>>801
ありがとです。
詳細な説明があるサイト知りませんでしょうか。
803800:02/09/12 16:50
>>799
すまぬ、勘違いしてた
仮数部・指数部
0.02e+12
だと、仮数部 0.02、指数部 12 = 200000000 ぐらいか?(0適当)
勘違いは、仮数部・指数部が逆だと思ってた
(´-`).。oO(800ゲットにうかれてたんだろうな…)
804800:02/09/12 16:55
あっでも普通は 0.2e+11 になるから「プ」ぐらいならいいのか
ん、2.0e+10 か? 処理系によるのか?
805デフォルトの名無しさん:02/09/12 18:26
まぁ、どうでもいいんだけど、
0.02e+12なる表記が出てくることってあるの?
そもそも、こういう表記って表記の定義としては正しいの?
806デフォルトの名無しさん:02/09/12 18:26
0.02e+12=0.02×10^12

2e10 って書いても同じ

808799:02/09/12 19:07
例えをそんなに問い詰められても・・・
わかんないから聞いたのに・゚・(ノД`)・゚・
Ae±B=A×10^±B
0.00001 って長く書くよりは、 1.0e-5 って書いた方が桁数がわかりやすい
799はいじめられっこ
0.02e+12を笑うやつが2.0e+10とかいうのか?
有効桁数を問題にしたいときは 0.02e+12 とか出てくるかも。
あと、5.2e+10 と 4.8e+11 を比べるより 0.052e+12 と 0.480e+12
のほうが解りやすいとか。
800もいじめられっこ
815デフォルトの名無しさん:02/09/12 20:06
便乗で質問です。
C++のcoutでfloatなんかの数字を表示するとき、
4.8e-3 みたいな表示を禁止して、常に
0.0048…みたいな表示にするのにはどうしたらよいのでしょうか?
あと表示の有効桁数を指定することも出来るのでしょうか?
>>815
指数表示をやめる・・・・・fixed
有効桁数・・・・・precision(n)
817デフォルトの名無しさん:02/09/12 21:48
>816
Thanx!できましたよ。
818デフォルトの名無しさん:02/09/12 22:00
ところで、
cout.setf(ios::fixed);
cout.precision(8);
みたいに変更した後、設定をデフォルトに戻したい場合はどうすれば宜しいのですか?
>>818
cout.unsetf(ios::fixed | ios::scientific);
cout.precision(6);

precisionは返り値として元の精度を返すので、それを保存しておいて
あとでprecisionに与えてもよい。
while( cin >> no >> ma >> en ){
 students.push_back( Student(no, ma, en));
}

こういうコードよく見るけど(マ板からの引用)、
たとえば、noの入力が失敗した場合、
続く「cin >>ma >> en」(ただし、cinはfailになってる)は
問題ないの?
俺のg++では、どこで入力に失敗しても、
変な動作を引き起こさずにすんなりwhileを抜けてくれるんだけど、
それは標準で保証されてることなのかな?
誰か知ってたら教えて。
>>820
cin >> no >> ma >> en は
((cin.operator>>(no)).operator>>(ma)).operator>>(en)と同じに
なると思うから、cinが失敗した所でoperator>>が働かなくなる
ようにされているのでは?
822820:02/09/12 23:56
>>821
レスありがとうございます。
そうですね。それで、疑問なのは、
cinがすでにfailになっている場合、
cin >> x;
は、「何もせずにcinを戻す」のか、
何かするのか、あるいは、本当は
未定義なのかということなのです。
すみません。
823デフォルトの名無しさん:02/09/13 00:40
>819
Thanx!早速試してみたいと思います。
>>822
cin.fail()がtrueの時、cin.clear()を行うまで、ストリームの処理を行わないこと
が保証されているようです(C++標準ライブラリP573)
見事にcinがスキップされるね。(gcc3.2)

#include <iostream>

int main()
{
int i;

std::cin.setstate(std::ios::failbit);
std::cin >> i;
}
>>825
例外を投げて欲しければ

iostate exceptions(iostate except);

でマスク外さないと。
>>826

単に>>824の確認してるだけでしょ?
vectorって自己参照ポインタって使えないんですか?
VC5.0ではじかれますた
こんなかんじ
class foo{
・・・
  foo* pParent;
  vector<foo*> pChild;
・・・
};
できないのでfoo** pChildにしますたが・・・
(メモリ管理自力(泣めんどくさい怒))
829デフォルトの名無しさん:02/09/13 22:19
ageてみつ
vector<class foo*>?
>>828
それに何の問題が??

参考までに、

#include <vector>

using namespace std;

class foo{
  foo* pParent;
  vector<foo*> pChild;
};

int main(){ return 0; }

は、VC6、BCCで通りますた。
bcc5.5.1で通りますた。
もしかして、thisをpChild.insert()するとか?

それは何故か知らんが、VC6だったら
vector<foo> pChild;
で通るかと。
と思ったら違った。。。
>>833
意味が変わってる
using namespace
を何も指定されていない状態に戻すには?
ない
{
  using namespace hoge;
  // 有効
}
// 無効
class foo
{
protected:
  type obj;
  foo* p;
public:
  hoge(){p->obj=something;}<−−−−−−*
};
*って外部からobjを操作してることになるんですか?
VC5.0だと通りますたが・・・ちょっと不安
objって何
841839:02/09/14 12:26
>>840
obj:何らかの型のオブジェクトです

hoge()の呼び出し元インスタンスと違うインスタンスのpを介して
protectedにアクセスできるのか?ということです
この日本語だと外部アクセスな気がしますが・・・
んで、VC5.0だと通っちゃうんですよ(動作も意図したとおり)
あーそういうことか。

アクセス保護はクラス間の約束でしかない。

以上。
843839:02/09/14 12:53
>>842
レスありがとうございます
844デフォルトの名無しさん:02/09/14 17:01
質問です。クラスの static メンバ変数のデストラクタが呼ばれないのですが、
何かいい方法はないでしょうか?volatile をつけても駄目でした。
コンストラクタで OS からリソースを確保するクラスは
static メンバ変数にしては駄目なのでしょうか?

以下は確かめに使ったソースです。
#include <iostream>

class A{
public: A(){std::cout << "A()\n";}
public: ~A(){std::cout << "~A()\n";}
};
class B{
public: static A ainst;
};
A B::ainst; //<- コンストラクタだけでデストラクタが呼ばれない

void fun(){
static A a; //<- これはちゃんと呼ばれる
}

void main(){
fun();
}
よろしくお願いします。
グローバルで
A B::ainst;
じゃない
>>843
同じクラスのインスタンスのprivateメンバに触れないんじゃ
コピーコンストラクタなんて書くとき困っちゃうよね。
847845:02/09/14 17:14
ごめん迂闊だった
グローバルでやってるね
これでいいはずだと思ったけど・・・
デストラクタ走るのが main() のあとだからじゃないかな。そのタイミングだと
cout が生きてるかどうかも分からないし。
main()のリターンのあと?
処理系依存っておちはない?
850844:02/09/14 17:23
レスありがとうございます

>>845
ちなみにただのグローバル変数にした時も同じになります。

>>848
c関数 atexit() で、出来る限り最後までやってみたのですが、
main() のはじめに atexit() した関数が呼ばれたのが
上記例の fun() 内部の a のデストラクタ呼出し後で、
ここまでは確認できたのですが…

もしスタートアップルーチンが、コンストラクトとデストラクトを
逆の順番にやってくれているとすれば(希望的観測)、
コンストラクタでは std::cout が生きていて
デストラクタで生きていないっていう事は無いような気がするのですが…
デストラクタで適当にファイル作って、呼出されてるかどうか
試してみては。
852844:02/09/14 17:28
ぎゃふん! >>848 さんの言っている事が正しかったです。

std::cout が破壊された後でした。
printf で同じ事を書いたら、ちゃんと呼ばれている事が確認できました。

お騒がせしました。ありがとうございあした。
853849:02/09/14 17:29
そうすると外部変数ってのはmain()始まる前に確保して
終わった後に解放するの?プロセスレジスタ(?名前忘れた)は
main()の前からプログラムに入ってるって事?
854849:02/09/14 17:31
>>852
main()から始まるわけではないんですね
なんかだまされた気分
855849:02/09/14 17:35
_cdeclとか_pascalとか関係ない?
856844:02/09/14 17:35
>>849
C/C++ のプログラムは(通常は)スタートアップルーチンっていう
ものがリンカによって付加されてますよん。
857849:02/09/14 17:38
>844
調べてきまつ
858849:02/09/14 17:41
スタックポインタの初期化
グローバルポインタの初期化
ROM to RAM コピールーチン
data 領域のコピー
bss 領域のゼロクリア
main 関数へのジャンプ
よーなことやってるんですか初めて知りましつ
FAQかもしれないけど、ウィンドウ(生成・破棄)のクラス化に関する質問です

要はウィンドウプロシージャがうまくクラス内に収まらないという話なのですが
staticで修飾しちゃうとメンバにアクセスできないし
CALLBACKじゃなくしてパブリックメンバにして、CALLBACKの方から呼んでやるっていうのも
ラッパークラス自体グローバルにしなきゃいけないし、そもそも隠蔽しきれてないし・・・

何かウマイ方法は無いもんでしょうか?
ATLのソースを見る
thisをHWNDに埋め込む。
彼女の膣に鰯を突っ込む
鰯→鮪
メンバに別のクラスのポインタを持つクラスを作ったとして
別のクラスのポインタが無効になったら自滅するように出来ますか?

例えばこんな風にして

class A {
};

class B {
  A* child;
public:
  B(A* a) { child = a; }
};

A* testA = new A;
B* testB = new B(testA);

Aのデストラクタが呼ばれたらBも一緒に死んでいくような・・・
>>864
できない。Observer/Obsavable パターン使え。
AにReference Counterとフラグ付けて、デストラクタの代わりに
A::Releaseをよびだして、そこでフラグをたて、RefCountをへらして、
Bの方では適当にフラグをポーリングすればええんでないかい?
867デフォルトの名無しさん:02/09/14 20:55
自作クラス用フレンド演算子
std::ostream& operator<< (std::ostream& lhs, const myClass& rhs)
を定義した時、これが呼ばれてほしくない場面で呼ばれてしまいます。
通常は
myClass myClassInstance;
std::cout << myClassInstance;
を想定していて、これはうまく動くのですが、インスタンスの存在するアドレスを確認したくて
std::cout << &myClassInstance;
と書いた場合まで、上の演算子が呼ばれます。
operator& () はオーバーライドしてないし、したくありません。
これは operator<<(std::ostream& lhs, myClass rhs);
にする以外でうまく解決する方法はあるでしょうか?
コンパイラ変えてみたら
>>867
std::ostream& operator<< (std::ostream& lhs, const myClass* rhs)
を作るとか。
PCだったら少なくとも3つのコンパイラは入れるよ。
>>870
includeとかlibみたいな環境変数がコンフリクトしてマズーなことになったりしない?

っていうか今時そんな環境変数でディレクトリ与えるのはもしかして主流じゃない?
環境変数はMSに遠慮してどこも使わなくなったね
>>872
BCCは-Iとかでディレクトリを与えてたな。gccはどうなってるの?
>>873
bccもgccも設定用ファイルがあるよ
MSは自社製品でconfrict起こすからな<環境変数
876無能:02/09/15 10:34
mapのデータに関数ポインタ渡してキーに関数名入れて呼ぶと楽しいよ
>>873
引数で -I, -L を使って渡すか specs という設定ファイルに書いておく。
bcc で使ってる bcc32.cfg の高機能版みたいなもんだ。
>>874 >>877
サンクスです。

じゃ、VC++/bcc/gccの混在も十分可能なのか。どうしよっかな〜。
iniファイル管理クラスを自作していてつまづいちゃったんですが
iniファイルみたいな3層構造([section]->key->value)を
うまく管理するにはどうしたらいいんでしょうか?

stlのmapにmap持たせようとしたり、色々やってみたんですが
僕の脳味噌じゃちょっと無理みたいです...

要件としては、iniファイルの内容を何らかのカタチでメモリ上に保持して
「[section]->key」でアクセスすると「value」が返ってくる様なモノです
もっと言っちゃうとVCLのTIniFileみたいなモノです

皆さんのお知恵をお借りしたいです
(「BCB買え」とかは無しでお願いします...)
>>879
map に map 持たせろ。
881879:02/09/15 14:29
>880
うー...頑張ります

ところでこれはCの質問だと思うんですが、ついでにお願いします

char temp[] = "aaaa\0bbbb\0cccc\0dddd\0\0";
という文字列があったとして、aaaaから順番に取り出していきたい場合

std::map< std::string, std::string > mymap;
while( 0 < strlen( temp ) ) { // \0\0 が 0 であることを期待して
  mymap[temp].insert("test"); // std::stringが\0までを文字列と扱ってくれると期待して
  temp = strchr(temp, '\0') + 1; // 最初の\0までを削除したい
}

で期待通りの動作をしてくれるでしょうか?
ちょっとwhileが絡んでくると、怖くてテストランできない...
>>879
COMPOSITE にすれば?
ini ファイルというよりレジストリになるからちょっとオーバースペックか?

直前の話題とかぶるけど、なんで MS は VC の設定にレジストリ使わないんだろう?
レジストリは階層構造つきの環境変数的な意味合いじゃなかったんだろうか?
他社への嫌がらせなのかな?
883879:02/09/15 15:35
>882
それってデザインパターンですよね
日曜PGなので理解が浅いですが、実装できるか頑張ってみます

そりゃそうと>881じゃコンパイル通らないですね...
ちょっと長いですけど実コードから抜粋

メンバ変数 std::map< std::string, std::map< std::string, std::string > > Entry;
に、Entry[section][key] = value の形でデータを収めたい

 コードは次レス(入りきらなかった...)

パッと見ておかしなところがあったら教えて下さい
よろしくお願いします
884879:02/09/15 15:35
char* SecTemp = (char*)calloc(sizeof(char), 2048);
DWORD hRetSec = GetPrivateProfileSectionNames(SecTemp, sizeof(SecTemp), FilePath.c_str());
if (hRetSec > 0) {
  char* KeyTemp = (char*)calloc(sizeof(char), 2048);
  while(0 < strlen(SecTemp)) {
    DWORD hRetKey = GetPrivateProfileSection(SecTemp, KeyTemp, sizeof(KeyTemp), FilePath.c_str());
    if (hRetKey > 0) {
      char* key = (char*)calloc(sizeof(char), 128);
      char* value = (char*)calloc(sizeof(char), 128);
      while (0 < strlen(KeyTemp)) {
        strncpy(key, KeyTemp, strcspn(KeyTemp, "=")); // "AA=aa\0BB=bb\0CC=..."の"AA"にあたる部分を取り出す
        KeyTemp = (strchr(KeyTemp, '=')+1); // "AA="の部分を削除(前詰め)
        strcpy(value, KeyTemp); // "aa\0BB=bb\0CC=..."の"aa"にあたる部分を取り出す
        Entry[SecTemp][key] = value;
        KeyTemp = (strchr(KeyTemp, '\0')+1); // 最初の\0までを削除(前詰め)
      }
      free(key);
      free(value);
    }
    SecTemp = (strchr(SecTemp, '\0')+1); // 最初の\0までを削除(前詰め)
  }
  free(KeyTemp);
}
free(SecTemp);
> パッと見ておかしなところ
3行目以降見てないけど…

> char* SecTemp = (char*)calloc(sizeof(char), 2048);
> DWORD hRetSec = GetPrivateProfileSectionNames(SecTemp, sizeof(SecTemp),
sizeof はいやん。
リークし捲りなので、std::stringを使おう。
887879:02/09/15 16:06
> DWORD hRetSec = GetPrivateProfileSectionNames(SecTemp, sizeof(SecTemp),

DWORD hRetSec = GetPrivateProfileSectionNames(SecTemp, sizeof(*SecTemp),
                                          ~~
でした...

(char*)calloc(sizeof(char), 2048); はマズイですか?
callocって「バイト数*長さ」で領域確保するんだと思ってましたがどうなんでしょう?
888879:02/09/15 16:10
あと>886は無理じゃないですか?
GetPrivateProfileSectionNames関数にstd::string渡せないし
実体渡ししたとして、その挙動(ポイント先の確からしさ)は保証されてないし
889879:02/09/15 16:12
>888
× 実体渡し
○ 直アクセスでポインタ渡し
char* SecTemp; なら、
sizeof(SecTemp) -> 4
sizeof(*SecTemp) -> 1
891879:02/09/15 16:21
あそうか、ポインタがポインタ持ってるんだから
sizeof(**SecTemp)か......な?
全然理解が足りてないですね僕...
>>888
そういうときはフツーstd::vector<char>を使う。
char t[1024]のときtの型はchar[1024]で、sizeof(t)は1024
char *pなら、pの型はchar*, (*p)の型はchar、 (**p)はエラー。
sizeofで要素数が分かるのは配列(と構造体)のときだけ。
ポインタの要素数はsizeofではわからない。
894879:02/09/15 16:36
>893
理解しました...
では
char* SecTemp = (char*)calloc(sizeof(char), 2048);
なら
(sizeof(char)*2048);
が正解ですか?

>892
でもstlのコンテナ群って、自分のインターフェース以外が内容を書き換えちゃった場合
その後の挙動は保証されてないですよね?
sizeof(char)は常に1だから、普通は単に2048とする。
(普通、はdefineとか使うんだろうが。笑い)
>>894
vector<T> (T != bool) の内部データはTの配列として使えることが保証されてる。

> (sizeof(char)*2048);
正解。…だが、 sizeof(char) は常に1なので単に2048でも可。
あと意味的には calloc( 2048, sizeof(char) ); が正しいのではなかろうか。
897879:02/09/15 16:46
恥かいたけど1つ(2つ)賢くなりました
ありがとう
文字ベースのC++の(簡単な)入門が終わりました。
これからBCBでGUIなんかやりたいのですが、
よい参考書を教えていただけないでしょうか。
>>898
Delphiの参考書ならなんでも可。
Object Pascal->C++の手動コンバートはなかなか面白いよ。
>>896

> vector<T> (T != bool) の内部データはTの配列として使えることが保証されてる。

ソースきぼん。以前、別所でその問題について議論されてたのを
思い出した。
901896:02/09/15 19:10
More Exceptional C++ の48ページによると
> This was fixed in 2001 as part of Technical Corrigendum #1 to
> the C++ standard, which now requires that the contents of
> a vector are stored contiguously, just like an array
とな。いや、俺もTC1の現物は見たこと無いんだけど。
>>900
Effective STL に書いてある。

ANSI C++ の規格書には記述がないんだが、後で採択された amendament に
書いてあるそうだ。(俺は確認してない)
903デフォルトの名無しさん:02/09/15 21:10
デバッグすると,ある変数の値に-1.#IND000000000と入っていたのですが,これは何を意味するのでしょうか?
(INFなら無限大なのは知っています)
よろしくお願い致します
904898:02/09/15 21:12
>>899
マジすか?Pascalなんてわかりません。(涙

知りたいのは、GUIまわり(コンポーネントって言うんですか)なので、
Pascalわからないでもよかったりします?
905デフォルトの名無しさん:02/09/15 21:27
>>903
不定値(#IND)
906デフォルトの名無しさん:02/09/15 21:28
>>903
インド人(#IND)
>>904
899です。
俺もDelphiは全くやる気はないけど、何せBCBのいい参考書が全然ない
ですからね。VCL部分は全くと言っていいほど共通なので、必ず役に立ち
ますよ。

ただ、C++には独自の関数を多数備えているので、VCLでできる事でも
C++でやった方が良い場合もいくつかあります。

Object PascalとC++間のコンバートには一種の規則のようなものがあり
ますが、それをうまくまとめたHPをまだ知りません。実際に試してみられ
るのが一番の近道です。

俺はここでよく質問しています。
「C Builder相談室 Part3」
http://pc3.2ch.net/test/read.cgi/tech/1016065855/
コンストラクタで例外投げてくる可能性がある関数を呼ぶのってマズいですよね・・・

インスタンス生成時に1回だけしか呼んで欲しくない処理を実装したいんですけど
何かウマイ方法はないですか?
それとも複数回呼ばれた場合の処理を盛り込んだ方が賢いですか?
> コンストラクタで例外投げてくる可能性がある関数を呼ぶのってマズいですよね・・・
何故?
それがインスタンス生成に絶対欠かせない関数呼び出しなら、
失敗して例外を投げた時はコンストラクタも失敗とするべきだし、
上手く呼び出せなくても何とかなる関数なら、コンストラクタの中で
try - catch で適切に対処すればよいだけ。
>910
もし例外が起こりうる関数より下でnewとかしてた場合
デストラクタで無効なdeleteしちゃったり
最悪デストラクタが呼ばれない(コンストラクタが完走していないので)
とかいう事になっちゃいませんか?
>>911
Effective C++ とか読んだ方が良いかもしれんな。コンストラクタ中で例外が
発生した場合には、対応するデストラクタは呼ばれないことが保証されている。
したがって、コンストラクタ中で後始末が必要な操作をする場合には

1. コンストラクタ内に try - catch を書いて後始末
 catch した後で throw; で例外をさらに外に投げる

2. メンバ変数やローカル変数としてスマートポインタを使う

いずれかで攻める。
913909:02/09/15 23:44
なるほど
ありがとうございました
914904:02/09/16 00:09
>>907
>>908
ありがとうございました。だいぶわかってきました。
(それにしても、BCBは不人気なのかと心配になってきました。)
>>914
BCBが不人気というよりも、Delphiの出来が良すぎて皆そちらに流れて
しまうからでしょう。

もしくはC++使いはVisual C++(.NET)に流れてしまいます。結果として
BCBユーザーは少なくなってしまっているのかもしれません。

VCLはObject Pascalで書かれているので、C++との相性に今一つ難が
あるような気がします。しかし、それでも無理矢理にでも他言語に介入
できるのはC++の大きな強みだと思います。

BCBに慣れたら、Visual C++(.NET)への移行もできます。でもVCLが
便利なので、MFCが嫌になるでしょうけど。
横から便乗質問。

俺は半分趣味のMFCプログラマ(全然人気のないシェアとか書いてる)
なんだけど、.NETになって迷ってる。(プロじゃないのに質問すまん。)
MFCのサポートは打ち切りらしいし、マネジッドでC#もどきをするなら、
いっそC#の方がいいのかとも思うし。
でも、C++は好きで(なじんでて)捨てるつもり気にはなれない。
結局、Builderに行こうかなあとも思うんだけど、いまいちマイナー感が。
やっぱり、参考書籍の少なさや、Delのおまけって感じが少し不安。
でも>>915なんか見ると、やっぱ、BCBでいいのかとも思うし。

VC++/MFC屋の人は、どうするつもり?
>>916
> MFCのサポートは打ち切りらしいし、
VC++.net には新バージョンの MFC 入ってるけど。
>>916
C#も結構イイよ。
マクロやら関数宣言やらよく使うインスタンスにextren
つけたりしている.hファイルをほぼ全ての.cppでインクルードするのは
何かまずいことがありますか?
あ、他の.hファイルでインクルードする時は
#define HOGE
#include "hoge_def.h"
#undef HOGE
で"hoge_def.h"側でHOGEが定義されてたらexternを避けるとしてます
>919
逆でしょ
共通ヘッダファイルに

#ifndef ___hoge_def
#define ___hoge_def
  (内容を適当に)
#endif // ___hoge_def

としておけば、多重定義にならない
>>919
「ほぼ全ての.cppでインクルード」っては、ヤだな。
機能ごとに別ファイルに分類して、必要なものだけを
インクルードすべきじゃないのか。
922デフォルトの名無しさん:02/09/16 10:30
乱数を均等に作るにはどうすればいいですか?
3600の内、1〜15を当たりにすると1/240に収束するのに
7200の内、1〜30を当たりにすると1/280に収束します。なぜ?
疑似乱数生成器は何使ってるの?
>>922
好みのテーブルを作れ
つか、均等に(等間隔で)出てきたらそれはすでに乱数ではない
925デフォルトの名無しさん:02/09/16 10:55
例えばRAND_MAXが32767だったら
3600で割った余りは1〜367が選ばれやすいから
均等でなくなるってことですか?
>>925
そう。単純にはその余りの部分が出たら捨てるといい。
927デフォルトの名無しさん:02/09/16 11:07
クジを32768本にして当たりを136本にしたら
ちゃんと1/240に収束するようになりました。
もっとスマートな解決法があればよかったのですが・・・
なにぶん初心者なもので。
根が深い問題だからスマートな解決法はないと思ったほうがいいよ
一番スマートなのは剰余から除算に変えること。
ただ、整数で演算を行うと誤差が出てくる。
余りがその誤差に転化しただけでは?
>>930
剰余は乱数の性質を変化させるけど、
除算は乱数の性質を変化させない。
除算後に表現できる数値の範囲で精度が保たれる。
>>930
乱数ジェネレータの種類によるけどね。
普通の実装は剰余法だから、普通は931の言うことは正しい。
933デフォルトの名無しさん:02/09/16 11:32
インラインメンバ関数を、実装をクラス宣言と一緒じゃなくて別に書く場合、
"inline"キーワードは宣言と実装のどっちに書くのが正しいんですか?
どっちに書いてもVCとBCCではOKみたいだけど、ちょっと気になるので。
オブジェクト指向ってなんぞや?
>>932
ためしてみたが偏ったよ。
936932:02/09/16 11:42
なにが?
>>935
試したソースを出せ。
何か勘違いしてるだろおまえ
>>933
どっちに書いてもOKじゃなくて、
どっちに書いても無視される。
どっちでもいいはず。
漏れは実装側に inline を書きます。inline の無い実装が
ヘッダにあると気持ち悪いので。
>>935
偏るのは当然だと思うが
>>939
実装にinlineを書くと同じコンパイル単位にある関数にしか展開されないはず
除算によって・・・って具体的にどんなコードになるの?
わかってる人(プ)書いてみてよ
943デフォルトの名無しさん:02/09/16 11:52
inlineて#defineと同じじゃなかった?
コンパイラから見えないと、展開できなかったと思ふ
アクセサなんかは .h に入れないと意味ナイト
>>941
inline を宣言側と実装側に書いた場合とで振る舞いが変わってくるという
ことでなのしょうか。どちらの場合でも実装は .h ファイルに書きますよね。
>>942
バーカ。お前なんかに見せてやんねーよ!
素人は除算で十分。
>>942
rand() / (RAND_MAX / double(max));
rand() * (1.0 / RAND_MAX) * max;

普通に↑じゃないのか?

>>945
その除算を知りたがっているのでは

と、マジレスしてみるテスト。
947943:02/09/16 11:59
すみません、ageてしまいました。

>>944
いや、>>941さんは .cpp で inline 宣言するケースを言ってるのだと
.h で宣言とは別に inline にするのならばどちらも一緒
948939:02/09/16 12:00
>inline の無い実装が ヘッダにあると気持ち悪いので。
の補足ですが、ヘッダファイルで
class T { inline void foo(); };
void T::foo() {}
が気持ち悪いので
class T { void foo(); };
inline void T::foo() {}
としているという意味です。
949943:02/09/16 12:13
すまん、混乱してきた。

.h ---------------------------------------------
class T {
 int get0() { return 0; } // インライン展開される
 int get1();
 inline int get2();
 int get3();
};
inline int get1() { return 1; } // インライン展開される
int get2() { return 2; } // インライン展開される

.cpp ------------------------------------------------
inline T::get3() { return 2; } // このファイル内だけでインライン展開される

で、get1かget2かって話?
>>920
本題から外れるが、_ から始まる識別子は処理系が使うから避けた方が良い。
以前に、それでハマったことがある。

(それ以降は UUID 入れるようにした)
>950
処理系が予約してるのって「__〜」(アンダスコア2個)までじゃなかったでしたっけ?
だからあえて3個にしてるんですけど、実際どうなんでしょう
規格書には、「_ で始まる名前はグローバルな名前空間 (と ::std) で
使うために予約されている」 とある。
あと、「__ を含む名前、または _[A-Z] で始まる名前は、任意の用途で
使うために予約されている」とも書いてある。
>>951それはC++で予約されてる名前だろ
_から始まる名前(2つ、3つ連続している物も含む)はC言語の頃から予約されてた
んで、C++になって明示的に_2つが予約されて、C言語用のキーワードと差別化が
計られた。

_3つ以上が予約されているのは現在も変わらず。
WyvernでMP3聞きながらコンパイルしてる漏れは逝ってヨシですか?
>>954
漏れも昔よくやってた。Pentium/120MHzのノートでな(w
956teset:02/09/17 03:41
double d;
__asm {
 movq d, mm0
emms
}
cout<<d<<endl;
957デフォルトの名無しさん:02/09/17 23:22
VBのVariant型変数と同じように扱えるC++のクラスってどっかに落ちてないかな。
Win32SDKのVALIANT使え。
>>957
boost::any とか。c++なので当たり前だがキャストが
色々要ってVariantよりは面倒だけど。
960デフォルトの名無しさん:02/09/17 23:55
CからC++への差分だけを学習させてくれ
せめてクラスは全部objectだったら良かったのにね。
962デフォルトの名無しさん:02/09/18 00:20
conservation
すべての親がvoidオブジェクトと考えるのはどうだ。
>>963
でvoidオブジェクトはどのようにして扱う?
>>960
柏原正三「標準C++の基礎知識」(ASCII)
っつー本で俺は学んだが。ちょうどC++を学びたいCプログラマ向け。
>>963
ということにしたいのですね :-)

…はともかく、void じゃなくて void* だよな。
全てはストラウストラープ氏の碁石のままん
(´д`)ママン・・・
いまさら文法の不備を指摘したところでもう手遅れ。
>>966
publish()メソッドで本を出版します
http://pc3.2ch.net/test/read.cgi/tech/1028553308/
でややすれ違いを指摘されたので、、こちらで。

>374 名前:デフォルトの名無しさん sage 投稿日:2002/09/18(水) 03:03
>オブジェクトを直接宣言する場合と、
> CTest oObj(Hoge);
>一旦ポインタの形で宣言しnewする場合は、
> CTest* pObj;
> pObj = new CTest(Hoge);
>どのように使い分ければいいのでしょうか?
>
>375 名前:デフォルトの名無しさん sage 投稿日:2002/09/18(水) 03:10
>スコープを外れても残したい時はnew。
>きっとここよりC++スレ向きの質問。

staticのようなイメージで捕らえればよいでしょうか?
Cで、autoな配列(int hoge[10]を使うべきか、
malooc(int *p=malloc(10*sizeof(int));)を使うべきかは
割と簡単に分かるとおもう。ぶっちゃけると、前者が
CTest oObj(Hoge)で、後者がnew CTest(Hoge)。
>972
おおよそのイメージがつかめました。
これからMDIのソースを見て勉強します。
どうも有り難う。
>>973
あれでわかるなんてすごいな。

> Cで、autoな配列(int hoge[10]を使うべきか、
> malooc(int *p=malloc(10*sizeof(int));)を使うべきかは
> 割と簡単に分かるとおもう。ぶっちゃけると、前者が
割と簡単にわかるというけど、これ難しいと思うんだけど。
>974
スタックに置かれるか、ヒープに置かれるか、
その辺の違いだと判断しました。
976972:02/09/18 04:51
そーかー、漏れはCでポインタバリバリのあとにC++に逝ったからなぁ。
今では危ない仮定なのかな?
977デフォルトの名無しさん:02/09/18 10:11
コンパイラ実装に関する質問です。
テンプレート関数なキャスト演算子を定義したテンプレートクラスの実体を使ったとき、
VC6だとコンパイルは通るのですが、実行時にプログラム自身が落ちてしまいます。
BCC だとちゃんと対応する型に変換できるのですが、
これは VC が馬鹿なのか、BCC が融通を利かせすぎなのか、私の書き方が間違っているのか
どれなのかわかりません。この動作は標準では許容されるのでしょうか?

template<typename T>
class TemplateClassX{
 private: T val_;
 
 public: template <class U>operator U(){
  std::cout << typeid(U).name();
  return val_;
 }
};

void main(){
 TemplateClassX<int> i = 10; // ここはそういうコンストラクタがあると思ってください。
 long l = i; // vc6 だとプログラムが落ちます、bcc ではちゃんとキャスト演算子が展開されるようです。
}
>>977
特におかしい所があるとは思えん。
コンストラクタが間違っているのか、あるいは
VCのtypeid(long)が壊れているか、だろうな。
979!963:02/09/18 12:53
>>966
Hoge *が指すのはHogeかそのサブクラスである。
ならばvoid *が差すのはvoidかそのサブクラスであるとするのが良い。
という事でないかと。
>>977
> std::cout << typeid(U).name();
この行を削っても落ちるね。
VC はメンバ関数テンプレートの展開が甘いんじゃないかな。
>>960
差分「だけ」というが、C++ - C >>>> C という罠
>>979
void*はvoidのポインタではない罠
罠多すぎ。。
>>979
「voidを指す」の意味がわかりません。
void 型へのキャストって「変数(の値)が一度も使用されていない」
などの警告を回避する目的以外にどんな場合で使われるんだろう。
>>985
煽りじゃないが,一応void型じゃなくてvoid*型な。
>>986
?
あ?
(void)printf()?
>>988
printf() を void キャストするとどうなるんですか?
>>989
lint の警告(戻り値が捨てられている)が出なくなる。
・lintが静かになる。
・I/O error処理なしの糞Cプログラムに。
・そういうことにしたいのですね:)
あ、
・compilerが"pop"する確信を持てるようになる。
を忘れた(w
>>989-990
lint 対策ですか。関数の戻り値までチェックしてるんですね。
ありがとうございました。
994993:02/09/18 18:12
ありゃまちがえた、
>>990-991
新スレ立てれなかった。誰か立てて下さい。
996
997997!:02/09/18 19:37
↓お前が必ず立てろ。
998v(^・^)v:02/09/18 19:54
次スレだす
http://pc3.2ch.net/test/read.cgi/tech/1032345774/
スレ立ててから続きを書こうと思ったらOSが落ちゃったよ。
やっぱり次すれがたったのね。
ついで。
10011001
このスレッドは1000を超えました。
もう書けないので、新しいスレッドを立ててくださいです。。。