トップページ⇒tech
1001コメント302KB

C++相談室 part34

■ このスレッドは過去ログ倉庫に格納されています
0001v(^・^)vNGNG
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
テンプレートライブラリ(STL含む)に関する質問は
専用の別スレにお願いッス。

過去スレ、関連スレ、関連リンクなどは >>2-20 あたり
0797795NGNG
調べてるうちに、この問題についての議論を拾ったので貼っておこう。
ttp://gcc.gnu.org/ml/gcc/2004-01/msg02323.html
ttp://gcc.gnu.org/ml/gcc/2004-01/msg02341.html
gcc開発者側の言い分を勝手に要約すると、
「無名名前空間がstaticのかわりに使えるようにしたかったのは分かるが、
 現状の規格に従う限りそれらは意味的に違うものになってしまっている。
 最適化のために規格に則ったプログラムを犠牲にするわけにはいかない。
 今までどおりの"static"として扱って欲しいのなら、"static"と書け。」
という感じ。
gccの現在の実装を盾にしている感もあったのだが、
ソースを見ずしてそこを非難するわけにはいかない。

ついでに、標準委員会の関連する動きも貼っとく。
ttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#223
ttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#167
ttp://www.open-std.org/jtc1/sc22/wg21/docs/cwg_closed.html#174
cwg_active.html#223 ってのが最悪で、
「deprecatedだからどうなの?」っていう話が未だに決まってないらしい。
激しく萎えた。
0798デフォルトの名無しさんNGNG
別に削除されてもされんでもどうでもいいとオモタ
0799デフォルトの名無しさんNGNG
std::localeあたりに削除されてほしいstatic変数がいくつかあるが
きれいに消えるんだろうか?
0800デフォルトの名無しさんNGNG
消えてもせいぜい50kBくらいじゃないの?
消えたからって特になんの効果もなさそうな気が。
0801デフォルトの名無しさんNGNG
>>800
処理系によっては、いくつか main() 走る前にコンストラクタが動いて、
動的メモリ割当を行うオブジェクトがあったりする。メモリ管理に手を
入れる場合に、ひじょーに面倒臭い。
0802デフォルトの名無しさんNGNG
>>801
そんなオブジェクトも削除されるのか?
0803デフォルトの名無しさんNGNG
単なる関数ポインタ宣言なら「void (*pf)();」と書けますが、

「A」というクラスに「B()」というメソッドがあった場合の、
Bのポインタ変数の宣言を教えて下さいでつ。
0804デフォルトの名無しさんNGNG
A::*B
0805デフォルトの名無しさんNGNG
>>803
void B(); なら void (*A::f)();
0806デフォルトの名無しさんNGNG
>>805
あ、*の位置間違えた、と思ったら >>804 が書いてた。
0807デフォルトの名無しさんNGNG
今更ながらの質問なのですが、効率的なincludeの仕方ってあるんでしょうか?

例えばhoge.cppとhoge.hが共に、stdhoge.hを必要とする場合
hoge.hの先頭に#include<stdhoge.h>する方法と
hoge.cppの先頭に、stdhoge.h>hoge.hの順で#includeする方法がありますが・・・。

後者は他でhoge.hを使う場合にも同順でやらなければと不便で、今まで避けていましたが、
世のライブラリを見ると、特定の順序でincludeせよという物も多く、疑問に思った次第です。
0808デフォルトの名無しさんNGNG
普通両方でインクルードするんでは?インクルードガードしてないと
おかしなことになるだろうし、してあればコードの解釈は1回ですむ
からそこまで効率が落ちるってことはないだろうし。
0809デフォルトの名無しさんNGNG
>>807
ファイルは単独で意味を持つ方が望ましいという観点から見ても、前者がいい。

>世のライブラリを見ると、特定の順序でincludeせよという物も多く、疑問に思った次第です。
標準ライブラリがそうでないように、そういう注文を付けるライブラリは怠慢だと思う。
0810デフォルトの名無しさんNGNG
hoge.hをインクルードしたらstdio.hの関数が使えるってのは嫌な話だ。
0811デフォルトの名無しさんNGNG
>>810
C++スレでそんな事を嘆くべきかな?
テンプレートが記述されたヘッダをインクルードする時に、
避けられないことだと思うけどなぁ。
0812デフォルトの名無しさんNGNG
exportつかいてえ
0813デフォルトの名無しさんNGNG
関数ポインタを引数に持つCライブラリ関数に、
C++のstatic宣言されていないメンバ関数を渡して、
実行させることはできますか?

staticでないC++のメンバ関数の実行には、仮想関数など
ランタイム時に決定される種類のものがある。だから、
Cライブラリ関数がそれを関知して動作することは不可能
→ゆえにstaticしか通らない。

と考えているのですが。

0814807NGNG
皆さんレスありがとうございます。
とりあえず唯一解みたいのが無くて安心しました。。

>>808
私の使っている駄目なIDEだと、cppの方にincludeしてないと
入力補助が働かないので、実利の面からその考えは納得できます。

>>809さんのレスが、最も同感です。
ちなみに私が悩んだライブラリの筆頭がWTLです。

>>810-811
それもまた、もっともですよね…。かなり嫌ではあります…が。
0815デフォルトの名無しさんNGNG
>813
概ねその通り。

まあ、渡せない理由は
仕様的には、型が違う
実装的には、暗黙のthisが引数に含まれる
からだけどな。
0816デフォルトの名無しさんNGNG
>>813
仮想関数などを使っていなくても、C 風の関数ポインタは
"this"が何であるのかっていう情報を持っていないので、
C風の関数ポインタを用いてメンバ関数を呼び出すことは出来ません。
0817デフォルトの名無しさんNGNG
>>813
プログラミング言語C++ 第3版 15.5
> メンバポインタは、変数ポインタや関数ポインタとは異なり、
> メモリの位置を指すポインタではない。
> メンバポインタは、ポインタというよりも構造体オフセット、
> 配列の添え字に近い。
0818813NGNG
みなさんすみません。

最初、スレッドの初期化等を抽象化する基底クラスを
用意し、派生クラスではrun()メンバ関数のみを実装
すれば、コンストラクタ内部で自動的に
pthread_create(..., run, ...);
が呼ばれてスレッドが生成される...みたいな
スレッドライブラリを考えていたのですが....

スレッド生成はWin32ならbeginthreadex_だし、
Linuxならpthread_createだしで、けっこう相違が
あるので、隠蔽したいんですよ...。
どういう設計にするのが妥当でしょうか?

いままでCだけで書いて来たので、実際に応用しようと
するといろいろわからないことが...
0819デフォルトの名無しさんNGNG
>>818
スレッドで実行される関数に少なくともポインタが格納できるサイズのパラメータが渡せるはずだから、
そこに this を reinterpret_cast して渡してあげて、スレッドの開始関数 (static) では単に

static int ThreadProc(..., void* arg)
{
 return reinterpret_cast<ThisClass>(arg)->run();
}
0820デフォルトの名無しさんNGNG
>return reinterpret_cast<ThisClass>(arg)->run();
return reinterpret_cast<ThisClass *>(arg)->run();
0821デフォルトの名無しさんNGNG
>>818
どうでもいいけど、スレッドのクラスによるカプセル化は止めた方がいいよ。
ま、C中心だったのであれば、潔癖なカプセル化はしないだろうけど、念のため。
0822デフォルトの名無しさんNGNG
>>818
> スレッド生成はWin32ならbeginthreadex_だし、
> Linuxならpthread_createだしで、けっこう相違が
> あるので、隠蔽したいんですよ...。
差異の吸収はboostにやらせるのはどうでしょ?
0823デフォルトの名無しさんNGNG
>821
そうなの?漏れけっこうガチガチにカプセル化しちゃたけど
特に不便を感じた事はなかったな。。。
>818みたいに,いろんな場所で動かす事を考えると
大変になるって事?
それとも漏れのカプセル化がまだユルユルだったのかな。
0824813NGNG
うう、819さんのおっしゃることが理解できないんです。
すみません。
reinterpret_castを使ったスレッド生成関数の
startup_routineを作っても、pthread_createや
親クラスへもっていく方法がわかりません。

#include <stdio.h>
#include <unistd.h>
#include <pthread.h>

class Thread {
public:
 virtual int run(void *) = 0;
protected:
 pthread_t t_;
};

class TSub : public Thread {
public:
 TSub();
 int run(void *);
protected:
};

static void * stub_thread(void *pParam)
{
 reinterpret_cast<Thread *>(pParam)->run(pParam);
 return NULL;
}
(つづきます)
0825813NGNG
TSub::TSub()
{
 pthread_create(&t_, NULL, stub_thread, (void *)this);
}

int TSub::run(void *pParam)
{
 sleep(3);
 return 0;
}

我ながら....情けなくなるのですが、TSubのコンストラクタに
書いてある内容をThreadのコンストラクタかメンバ関数に
もっていきたいわけです。
0826813NGNG
ちなみに今まではUNIX/Win32でほぼ1vs1になるように
スレッドAPIを#defineで再定義していました。返り値なども。

ただ、スレッドプログラミングを進めるにつれ、
スレッドが使うヒープなどを終了時に自動的に回収したいとか、
pthreadそのままなのでprimitive過ぎて使いにくいとか、
いろいろ不満がでてきたのです。

Boost、恥ずかしながら今初めて聞きました。
ドキュメントを読んでみようと思います。
0827デフォルトの名無しさんNGNG
こうかな?
class Thread {
public:
 int Start()
 {
  return pthread_create(&t_, NULL, stub_thread, reinterpret_cast<void *>(this));
 }
 int Join(void** value_ptr = 0)
 {
  return pthread_join(t_, value_ptr);
 }
protected:
 static void * thread_func(void *pParam)
 {
  Thread *pThis = reinterpret_cast<Thread *>(pParam);
  return pThis->run(pParam);
 }
 virtual int run(void *) = 0;
protected:
 pthread_t t_;
};

class TSub : public Thread {
public:
 TSub();
protected:
 int run(void *) { sleep(3); return 0; }
};
0828デフォルトの名無しさんNGNG
上の
return pthread_create(&t_, NULL, stub_thread, reinterpret_cast<void *>(this));
の stub_thread は thread_func の間違い。

ただ、今から書くのならば
class IRunnable {
public:
 int run() = 0;
};
みたいなのを単独でインタフェイスとして定義して、Thread クラス本体と run を実装する
クラスを分ける方がよいと思う (Thread::Start の引数として IRunnable* を取る)。
0829813NGNG
>>828
キタ━━━━(゜∀゜)━━━━!!
最初思っていたことは上記のコードでできそうです。
ありがとうございました。

で。IRunnableの話なのですが、Thread I/Fとして
のclass Threadから、run()を追い出すとどのような
メリットがありますか?

まずThreadクラスのインスタンスを生成/管理する
ThreadFactoryとかThreadPoolとか作っておいて...

それらとは別に作っていたクラス
(例えばScreenManagerとか)で、値の監視的要素が
出てきたら、おもむろにIRunnableをくっつけて
run()だけ実装して、
ThreadFactoryに「スレッドにdispatchしてくれ」と
頼む、みたいな感じでしょうか。Start()が参加で、
Join()が脱退みたいな。
0830デフォルトの名無しさんNGNG
ここは頻繁にカプセル化するな厨が現れるな。
0831デフォルトの名無しさんNGNG
プログラムの規模によるんだよ
0832デフォルトの名無しさんNGNG
ThreadとかWindowとか、OSの機関にかかわる部分や特有の機能はカプセル化するべきじゃない。
Socketとかコンソールとか、どのOSでも似たような機能を備えていそうなものだけカプセル化するべきだ。
0833デフォルトの名無しさんNGNG
>>832
グローバル変数はアプリケーションインスタンスの
インスタンス変数って考え方でいいじゃん。
あとアクセス制御をどうするかって論点に絞るだけ。
0834デフォルトの名無しさんNGNG
カプセル化の是非はOOスレでやれ。
ここはC++でどうやるのがいいか悪いかを論じる。
0835デフォルトの名無しさんNGNG
>832
ポータビリティを重要視したライブラリを真っ向から否定ですか?
0836デフォルトの名無しさんNGNG
>>832
プラットホーム間のポータビリティとは限らんでしょ。
スレッドやソケットはさすがに微妙だと思うよ。
もろシステムコールじゃん。明らかに他のジャンルと異質。
0837デフォルトの名無しさんNGNG
>>835
ポータビリティはOSの特色を生かせない低賃金がする言い訳
個々のOSの特徴や性能を100%引き出してこそプロ
0838プッNGNG
CとかC++とかperlとか、
ポータビリティのある言語だからプロ向けじゃ(ry
0839デフォルトの名無しさんNGNG
ハードディスクの性能をフルにいかすには、ファイルシステムなんて(ry
0840デフォルトの名無しさんNGNG
移植性とか規格を隠れ蓑にしてる厚顔無知は確実に実在する
決して「切り込み隊長」的な仕事をしない
0841デフォルトの名無しさんNGNG
公然オナニー迷惑な「切り込み隊長」も確実に実在する
0842デフォルトの名無しさんNGNG
>>837
移植性を追及すべきか、アーキテクチャへの最適化をついきゅうすべきかを合理的に判断してこそプロ
0843デフォルトの名無しさんNGNG
追求を「ついきゅう」なんて書いちゃう俺はアマ
0844デフォルトの名無しさんNGNG
>>842
両立してこそプロ(の技量)
0845デフォルトの名無しさんNGNG
移植性は追求しろと
0846デフォルトの名無しさんNGNG
いやもうマ板の話の流れっつーか
0847デフォルトの名無しさんNGNG
>>841
無能ですね
0848デフォルトの名無しさんNGNG
何のかんの理屈つけては逃げ回るだけの敵前逃亡の専門家イラネ
0849デフォルトの名無しさんNGNG
なんのかんの理屈つけて、カプセル化、抽象化から逃げる池沼もイラネ

お前が出来ないからって、他の人も出来ないと思うな
0850デフォルトの名無しさんNGNG
なぜ荒れる(w
0851デフォルトの名無しさんNGNG
ホイポイカプセル化しとけ
0852デフォルトの名無しさんNGNG
夏休みが終わりに近づいてるから
0853デフォルトの名無しさんNGNG
>>849は、手段と目的を履き違える典型的な「切り込み隊長」(w
0854デフォルトの名無しさんNGNG
stringクラスには大文字を小文字に変換するメソッドとか
その逆のメソッドはありませんか?
MFC CStringのMakeUpper()やMakeLower()みたいな感じの。
0855デフォルトの名無しさんNGNG
ctype::tolower
0856デフォルトの名無しさんNGNG
std::transform(s.begin(),s.end(),s.begin(),static_cast<int(*)(int)>(std::tolower));

locale対応バージョンがうまく書けない。
0857デフォルトの名無しさんNGNG
面倒でつね… なんでメンバに実装されてないのかな…
0858デフォルトの名無しさんNGNG
>>857
派生クラス作っときゃええやん
使えるクラスができたら売るとか・・・
0859デフォルトの名無しさんNGNG
>>857
そりゃ、localeのせいだろ。
0860デフォルトの名無しさんNGNG
デストラクタで純粋仮想関数を呼び出したいのですがうまくいきません。
純粋仮想関数の中身を実装しないとコンパイル時に関数がないと言われるのですがなんででしょう?
↓ソースはこんな感じです。

#include <time.h>
#include <iostream>
class DyingMessage{
  virtual void say1() = 0;
  virtual void say2() = 0;
protected:
  ~DyingMessage(){
    ( time(NULL) %2 ) ? say1() : say2();
  }
};
class JiipanKeiji : public DyingMessage {
  void say1(){ std::cout << "なんじゃこりゃー"; }
  void say2(){ std::cout << "おらぁ死にたくないよ、死にたくない、死にたくないよ・"; }
};
class RAOU : public DyingMessage {
  void say1(){ std::cout << "我が生が(略"; }
  void say2(){ std::cout << "我が生涯に一片の悔いなし!ウオァァァアア!"; }
};
int main(void){
  JiipanKeiji jk;
  RAOU r;
}
0861デフォルトの名無しさんNGNG
>>860
~DyingMessage() が実行されるときには、ジーパンもラオウも既に死んでいる。
0862デフォルトの名無しさんNGNG
>860
コンストラクタとデストラクタ内では、仮想関数が仮想になれない。
デストラクタを仮想にしてそこに書くしか。
0863デフォルトの名無しさんNGNG
柴田望洋さんの、CプログラマのためのC++入門を買おうと思っているのですが
内容的に古いらしいのですが、大丈夫なのでしょうか?
0864デフォルトの名無しさんNGNG
>>861
まじで
台詞はいてからじゃないと名シーンが台無しに・・・。

>>862
すみません、virtual抜けてましたね。
でもデストラクタにvirtualつけてもやはりコンパイル通らないっす
って仰っているのはデストラクタにvirtualつけろってことではない?

それで実験としてDyingMessageのsay1とsay2を
cout << "犯人はヤス"; と定義してみたらと、
ジーパンもラオウも「犯人はヤス」しか言わなくなりました。
な、なにゆえ?
0865デフォルトの名無しさんNGNG
>>864
処理の順番はこうなる。
 DyingMessage()→RAOU()→ラオウの生涯→~RAOU()→~DyingMessage()
~RAOU()のタイミングでラオウは天に還ってしまう。
0866デフォルトの名無しさんNGNG
コンストラクタとデストラクタの中では、
関数呼び出しは(virtualであっても)「そのクラス」として行われるよ。
DyingMessageクラスではsay1, say2の中身は存在しないから、
コンパイラのメッセージは正しい。
実行時にヌルポ(pure virtual function call)を出す実装もある。

細かい話をすると、デストラクタやコンストラクタが親クラス→子クラス
と渡るときに、vtblのポインタが書き換わる。

これ、Javaと逆だから、多言語を渡り歩く人は要注意ッス。
Java方式もまたそれで問題あるんだけどね・・・
0867860NGNG
>>865
中身(インスタンス)はRAOUだから、say1、2はラオウのものを呼んでくれてもいいのに( ´Д⊂ヽ

>>866
>細かい話をすると、デストラクタやコンストラクタが親クラス→子クラス
>と渡るときに、vtblのポインタが書き換わる。
まじですか。vtblのポインタが書き換わるんですか。
main関数内と ~DyingMessageでのジーパン、ラオウのインスタンスのメモリアドレスが一緒だったんで、
ジーパンとラオウのvtblのsay1、say2が呼び出されてうまくいくかと思ってたのですが納得です。


結局のところ、どうしよう。
~DyingMessage上でラオウのsay1が実行させたいのですが。なんか考えます。
ありがとうございました。
0868デフォルトの名無しさんNGNG
>>867
> ~DyingMessage上でラオウのsay1が実行させたい
そうはいってもそのときにはもうラオウは居ないから、
ラオウに追加したメンバは触れないぞ。

生きているうちに遺言を作っておいて DyingMessage に保持させるといいかもしれない。
0869デフォルトの名無しさんNGNG
>>867
~DyingMessageが実行される時には
「お前(ラオウ)はもう死んでいる」から
ラオウのメンバを無理矢理呼び出すのもダメだよ。
0870860NGNG
>>868
できれば、>>860のラオウやジーパンクラスのソースのようにsay1、say2のみを定義するだけで他は何も手を加えず、
後は親クラスのDyingMessageがsay1、say2を使って処理してくれるようなのが理想なんです。
できるだけ子クラスは記述しなければならないソースを減らしたいんです。
でも、確かにラオウは破棄されてしまうわけだから今回の場合は無理っぽいですね。

>生きているうちに遺言を作っておいて DyingMessage に保持させるといいかもしれない。
それはいいアイデアかもしれないっす。ありがとうございます。
0871デフォルトの名無しさんNGNG
C++のデストラクタは、リソース開放のためだけに使うと思ったほうがええよ。
0872デフォルトの名無しさんNGNG
>>858
std::stringの派生クラスを作る奴は糞。
0873デフォルトの名無しさんNGNG
class x : public std::string
{
public: ~x() { std::cout << "x::dtor" << std::endl; }
};

main()
{
std::string* p=new x();
delete p;
}


実行結果
x::dtor

問題なし。
0874デフォルトの名無しさんNGNG
>>873
環境は?
0875デフォルトの名無しさんNGNG
>>874
お前が気にするのはそこなのか?
この場合問題なのはデフォルトコンストラクタしか使えんことだろ。
0876デフォルトの名無しさんNGNG
>>875
実行結果
0877デフォルトの名無しさんNGNG
>>876
Oh! Me としたことが釣られてしまいましたNeー!
0878デフォルトの名無しさんNGNG
VC++6で.cppと.defファイルをDLLにコンパイルする方法を教えて下さい
0879デフォルトの名無しさんNGNG
VCのスレ行ってください
0880デフォルトの名無しさんNGNG
>>872
> std::stringの派生クラスを作る奴は糞。
まぁ、作るなとは言わんが、この場合は

tolower(std::string&);
toupper(std::string&);

っつーフリー関数にしておいた方が、何かと幸せになれる気がする。
0881デフォルトの名無しさんNGNG
boost/algorithm/string/case_conv.hpp
0882デフォルトの名無しさんNGNG
std::ifstreamで
std::ifstream fin("somefile");
char str[1];
fin.getline( str, 256 ); // この結果勝手に256に拡張されるっぽい
などとできてしまうのですけどこれって仕様ですか?
0883デフォルトの名無しさんNGNG
>>882
未定義動作です。
0884デフォルトの名無しさんNGNG
>>882
拡張をしないまま暴力的に 256 byte 書き込んできてしまうだけ
道路の拡幅工事を立ち退き交渉も予告もせずにおっぱじめるようなもの
何が起きるのかは、おそらくご想像のとおり・・・
0885882NGNG
一見ちゃんと動いてるようでもやっぱり危険なコードだったんですね。
今度から気をつけます。ありがとうございました。
0886デフォルトの名無しさんNGNG
>>872
uppercase_traits作るんでもいーけどさ、
stringとの混用を前提とする場合、他にどーしよーもねーだろ
0887デフォルトの名無しさんNGNG
>>886 >>880-881
0888デフォルトの名無しさんNGNG
>>886
そのuppercase_traitsって、何してくれるの?
0889デフォルトの名無しさんNGNG
>>886
>>880
でいいやん。
なんで継承したがる?

つうか良く考えろよ。今から分かりやすく説明するからな。

お前は機能XXXを追加したくなった。
機能追加は継承だという浅はかな考えからstringから派生することにした。

class MyString : public std::string{
public:
void XXX();

/* 他のメソッドは略 */
};

こうしちゃったらさぁ、機能XXXを使うには
必ずMyStringクラスを構築する必要が出来るよな

MyString mystr=std_string_variable;
mystr.XXX();

これってかなーりムダだよな。
0890デフォルトの名無しさんNGNG
>>889
ちっとも解りやすくないぞ。何が言いたいんだ?
アップキャスト後に追加メソッドを使うコンテキストでへ来ちまったら
ダウンキャストが必要になるのはどんな作りのクラスでも一緒やん。
継承を全面否定したいのなら、同意はしないが理解はできる。
0891デフォルトの名無しさんNGNG
>>890
馬鹿はスルーしろよ
0892デフォルトの名無しさんNGNG
STLのコンテナクラス(ここではstd::string)のデストラクタが
virtual じゃないんじゃね?

>>889はJava厨の釣りと見た。

0893デフォルトの名無しさんNGNG
いや、機能追加したいがためだけに実装継承するぐらいなら委譲で何とかしろってのがセオリーじゃないのか?
0894デフォルトの名無しさんNGNG
コンテナには委譲を使うのが基本だね
0895デフォルトの名無しさんNGNG
public std::string
↑
メソッド追加するだけなのにpublic継承してる所が釣り
0896デフォルトの名無しさんNGNG
>>893
機能追加つーたら継承そのものやんけ
なんで「異常」な手段に拘るんだよ
■ このスレッドは過去ログ倉庫に格納されています