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

【初心者歓迎】C/C++室 Ver.54【環境依存OK】

■ このスレッドは過去ログ倉庫に格納されています
0001デフォルトの名無しさん2008/05/14(水) 01:00:02
エスケープシーケンスやWin32APIなどの環境依存なものでもOK。
ただしその場合、質問者は必ず環境を書きましょう。
※sage禁止です(と代々スレに書いてありますが自己判断で)。
【前スレ】
【初心者歓迎】C/C++室 Ver.53【環境依存OK】
http://pc11.2ch.net/test/read.cgi/tech/1208989385/l50
【アップローダー】(質問が長い時はココ使うと便利)
http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/joyful.htm
0008デフォルトの名無しさん2008/05/14(水) 16:07:44
strncpy, snprintf, memcpy などの関数でサイズ引数を0にした場合の挙動って定義されてるんでしょうか?
やっぱり自分でチェックした方が無難?
0009デフォルトの名無しさん2008/05/14(水) 18:20:01
>>7
そのメッセージの前に警告番号とか出なかった?
あと警告やエラーはそれのみ?

>>8
それぞれの関数の仕様を確認すること。
「など」に対しては定義されてないので。
未定義や不定の条件に書いて無ければ、サイズ0もOK。
ただしサイズが負の数みたいな、
有り得ない値は逆に、何も書いてなければNG。
0010デフォルトの名無しさん2008/05/14(水) 18:31:03
size_tだから負の値はない。
それでももちろんsize_tで表現できる最大値とか明らかにおかしいだろって値は存在するけど。
0011デフォルトの名無しさん2008/05/14(水) 18:33:43
>>7
Hogeは具体的に何のクラス?
デフォルトコンストラクタがないとか値として持てないクラスじゃね?
0012デフォルトの名無しさん2008/05/14(水) 18:34:27
>>8
ありがとうございます。WG14/N843というのを拾ってきたので読んでみました。

snprintf() についてはサイズ0を指定してもよくて、その場合書き込み先バッファはNULLでもいいみたいです。
strncpy()とmemcpy()ではサイズ0の場合については何も書かれてないので、サイズ0もOKみたいですね。
サイズ0のときにバッファをNULLにしてもいいのかどうかまではちょっとわかりませんでしたが…。

あと、サイズはだいたいsize_tで指定するので負になるという心配はあまりなさそうです。
0013デフォルトの名無しさん2008/05/14(水) 20:26:17
>>12
サイズ0のときはNULLにして良いよ。
サイズ0なら、指定したバッファのアドレス自体にもアクセスしてはいけないから、
アクセスしたら関数側のバグになる。
0014デフォルトの名無しさん2008/05/14(水) 20:55:42
何も書かれてないということは、未定義動作じゃないのかね?
0015デフォルトの名無しさん2008/05/14(水) 21:44:07
派生クラスのコンストラクタから、 初期化リスト?経由で基底クラスのコンストラクタ を呼び、
そこから派生クラスで実装されている純粋仮想関数を呼びたいのですが、不可能でしょうか?
これが出来ると基底クラスのコンストラクタを再利用出来るし、違う処理(初期化)が必要な部分は
仮想関数の実装を変えるだけでいいので便利だと思ったのですが。
0016デフォルトの名無しさん2008/05/14(水) 21:52:47
>>15
できません
基底クラスのコンストラクタ実行中は派生クラスは未構築だからです
0017デフォルトの名無しさん2008/05/14(水) 22:10:34
>>16
やはりダメですか・・・
うーん。自分の設計が悪いせいか、基底クラスのコンストラクタ今一役立たずだな・・・
0018デフォルトの名無しさん2008/05/14(水) 22:18:57
>>7
>warningの意味は何なのか? 原因は何なのか? また、解決方法のご存知の方、回答お願いします。
英文のままですね。英文の意味が判らないのなら鼬害でしょう。
まぁ、静的なメンバ変数は明示的に実体化しないといけないので普通の環境でもリンクエラーになるわけですが。
0019デフォルトの名無しさん2008/05/14(水) 22:22:21
>>17
簡略化した例を示せば賢い人が答えてくれるかも

多分C++ではそういうときにはテンプレートの出番になると思うけど
0020デフォルトの名無しさん2008/05/14(水) 23:36:19
>>14
>何も書かれてないということは
いや、書かれていることになる

上の例で出ている関数などでバッファポインタとバッファサイズを取るものは、
[buf, buf+size) の範囲内がアクセス可能ということを要件としているので、
size==0のときはbufのアドレスが何であれ要件を満たすことになる

>>15
似たようなことをする方法はいくつかある

・仮想関数をvfuncとして、基底クラスにinit()などを用意して、
 派生クラスのコンストラクタから呼ぶ
  ※ 基底ctor -> 派生ctor -> 基底init() -> 派生vfunc()

・基底コンストラクタに関数ポインタ類を渡す

・templateクラスにして継承関係を逆にする
  ※ template<class T> class base : T {};
0021デフォルトの名無しさん2008/05/14(水) 23:40:30
ostringstreamクラスに、
ostringstreamオブジェクトの先頭に任意の文字列を追加できる関数ってありますでしょうか??
探しても見つからなかったのですが。
0022デフォルトの名無しさん2008/05/15(木) 00:02:36
>>21
こんなことならできる

int main()
{
using namespace std;
string t("abc");
ostringstream s;
s << "xyz";
s.seekp(0);
s << t + s.str();

cout << s.str() << endl;

return 0;
}
0023デフォルトの名無しさん2008/05/15(木) 00:07:18
>>21
一応ストリームなんだから、そういう操作は仮に出来ても勧められないな・・・

前後だけで良いならfront側とback側にstringstreamを持ってstr()時に
結合するラッパーを作るという手はある
超手抜きで書くと
struct {
  ostringstream front;
  ostringstream back;
  string str(){return front.str() + back.str();}
};

またはstd::list<std::string>で構築して、必要になった際に全結合するなど
0024232008/05/15(木) 00:10:53
リロードしてなかった
>>22が手軽で良いかもな

それと>>23のfront云々のところは素でボケてたので無かったことに・・・
0025デフォルトの名無しさん2008/05/15(木) 02:38:37
>>19-20
レスありがとうございます。
なるほど、テンプレートや関数ポインタですか。
しかしC++は奥が深そうですね・・・
0026デフォルトの名無しさん2008/05/15(木) 07:14:40
Yo Yo俺ニート!
002772008/05/15(木) 12:11:02
>>9
質問するのに肝心な部分を書いてませんでした。
warning C4251 がエラー番号に該当すると思います。
>>11
規約としてデフォルトコンストラクタ、デストラクタは定義
しなければならないのでその点は問題ありません。
>>18
>まぁ、静的なメンバ変数は明示的に実体化しないといけないので普通の環境でもリンクエラーになるわけですが
cppファイル内で実体化させているのか、という意味ならば実体化させているので
その点は問題ないように思います。
試しにstaticをはずしてみたのですが、同様のエラーでした。

NULLチェックやdelete処理などが面倒なので実体を持つようにし、かつ、1つのシステム内で
唯一1つのインスタンスしか使用しないのでstaticで良いじゃないか?
staticにするとわざわざどこかのクラスから参照やポインタで辿っていかなくても Foo::hogehoge
とアクセスできるから楽じゃないか?
と安易に思ったのが失敗だったんでしょう。
0028デフォルトの名無しさん2008/05/15(木) 12:14:39
C4251 だけ書いて内容書かないのは、こっちで調べろってこと?
002972008/05/15(木) 12:30:25
>>28
言っている意味がわからないのですが、こちらでどう調査しても
warning C4251: 'hogehoge : 'class 'Hogehoge' needs to have dll-interface to be used by clients of class 'Foo'
しかわからない
上記warningが発生した原因は特定インスタンスメンバをポインタではなく、static かつ 実体として持つようにした
というのは 7 で書いたつもりです。
言葉足らずのところはこちらのミスですので謝りますが。
エラー番号ではなく警告番号でしたが、どう調査してもC4251しかわかりません。
0030デフォルトの名無しさん2008/05/15(木) 12:40:36
>>29
Hohehogeの宣言を晒してくれなきゃワカンネ。
エラーが起こる最小のコードをup
0031デフォルトの名無しさん2008/05/15(木) 12:46:16
平均点の高い順に並べ替えて表示するプログラムを作りたいのですが、結果が表示されません;
どこをどのように直したらいいか教えてください。お願いします。

http://kansai2channeler.hp.infoseek.co.jp/cgi-bin/joyful/img/6554.c
0032デフォルトの名無しさん2008/05/15(木) 12:55:41
>>31
sort()とやらはgccの拡張機能である、関数内関数定義を行っているだけで呼び出していないから。
他にもいろいろ突っ込みどころだらけだが……
0033デフォルトの名無しさん2008/05/15(木) 12:57:32
なんか、ロジックをいろいろ寄せ集めただけっぽいな。
ソートを自分で書くのが目的なら、渡すデータ型に注意だ。
003472008/05/15(木) 13:00:59
>>30
そういうことですか!!
確かに質問するにあたって情報が足りなかったですね。

warningが発生するHogehoge最小ソースは

class Hogehoge
{
public:
Hogehoge(){};
virtual ~Hogehoge(){};
};

です。
0035312008/05/15(木) 13:05:37
>>32
main関数の前に
void sort(int *p,int n);
を付け加えました。

他に間違ってるところってどこですか?
0036デフォルトの名無しさん2008/05/15(木) 13:08:23
>他に間違ってるところってどこですか?
たくさん。あり過ぎて指摘する気にもならん。
まぁ、作った関数は呼ばなきゃ意味がないことくらいは判るだろうから、
後はコンパイラのエラーメッセージをよく読んで順に潰せ。
そうそう、gccを使っているだろうから、gcc file.c -ansi -Wall -pedanticすることをお勧め。
0037322008/05/15(木) 13:10:43
>>35
私の指摘をちゃんと読んでますか? 「関数呼び出し」って、理解できますか?
0038デフォルトの名無しさん2008/05/15(木) 13:11:36
class HogeHoge
{
public:
HogeHoge(){};
virtual ~HogeHoge(){};
};

class Foo
{
public:
static HogeHoge hogehoge;
};

int main ()
{
Foo myClass;

return 0;
}
問題なく通るけど…
0039382008/05/15(木) 13:14:35
VC++2005EE
0040322008/05/15(木) 13:15:08
>>34
>38だとhogehogeの実体を参照しないからエラーにならないかと。
Hogehogeだけ抜き出さずに、実際にそのエラーが出るソースを作って貼ってみては?
004172008/05/15(木) 14:08:53
さらに色々調査してみたところ、ソースコードというよりも環境が怪しい気が
してきました。
もう少し調べてみます。
0042デフォルトの名無しさん2008/05/15(木) 14:10:17
もうこなくていいよ
0043デフォルトの名無しさん2008/05/15(木) 15:58:58
>>7
C4251でググったりはしたよね?
0044デフォルトの名無しさん2008/05/15(木) 16:09:49
> HogeHoge(){};
> virtual ~HogeHoge(){};
セミコロン要らないだろ
0045デフォルトの名無しさん2008/05/15(木) 17:54:36
struct point{
double x;
double y;
};


struct point q[200];

memcpy(q,p,(n+1)*sizeof(struct point));

これってどういう事をやってるんですか?
0046デフォルトの名無しさん2008/05/15(木) 18:02:55
pが指す所から(n+1)*sizeof(struct point)バイトqの所にコピーしてる
0047デフォルトの名無しさん2008/05/15(木) 18:08:27
>>45
恐らくはstruct point * pがあるとして、
先ずはpoint構造体の要素数200の配列qを宣言している。
続いてその配列qに、point構造体(n+1)個分のデータを配列pからコピーしている。
この部分は、for (int ic = 0; ic < n + 1; ++ic) q[ic] = p[ic];とほぼ同等。
0048デフォルトの名無しさん2008/05/15(木) 18:19:35
すいません。

int func(int n,struct point p[],double d){
struct point q[200];

;
memcpy(q,p,(n+1)*sizeof(struct point));


}

みたいに構造体が引数で渡されています。
0049デフォルトの名無しさん2008/05/15(木) 18:21:52
>>48
「構造体」ではなく、「構造体へのポインタ」ね。つまりは、>47。
0050デフォルトの名無しさん2008/05/15(木) 18:24:31
なるほどわかりました。

実際のpの大きさがソースを書くときには不定なので、
for文での代入をしていないってことでしょうか?
0051デフォルトの名無しさん2008/05/15(木) 18:27:58
>>50
いや違う。pの大きさは、常に一定だ。何故ならpはポインタ変数だからだ。
pが指す領域のサイズについてはnに依存するわけだが、forループでも勿論巧くコピーできる。

では何故memcpy()を使うかというと、保守性よりも(見かけ上の)効率を優先したか、単に習慣か、
書いた人間にでも聞かないと判らないだろう。
0052デフォルトの名無しさん2008/05/15(木) 18:29:13
for文で1個ずつでもいいけど、丸ごと全部いっぺんにやったほうが早いべ
0053デフォルトの名無しさん2008/05/15(木) 18:42:40
いいえ、一概には言えません。まともなコンパイラにまともに最適化させてやれば恐らくは、目に見える速度差はないでしょう。
0054デフォルトの名無しさん2008/05/15(木) 18:46:59
書く量だって少ないし、コーディングも早いだろ。
0055452008/05/15(木) 18:49:17
いろいろ教えていただきありがとうございました。

0056デフォルトの名無しさん2008/05/15(木) 19:00:21
>>54
>memcpy(q,p,(n+1)*sizeof(struct point));
39文字
>for(int i=0;i<n+1;++i)q[i]=p[i];
32文字
0057デフォルトの名無しさん2008/05/15(木) 20:30:03
VC++でインラインアセンブリを使うとき、
疑似命令によくある、生データを直接コードに埋め込む事って、どのようにすればいいのですか?
テーブル参照のようなことを仕様と思ったのですが、やり方がよくわからなくて…
0058デフォルトの名無しさん2008/05/15(木) 20:34:29
>>53
逆に言えば
memcpyみたいな動作をする命令があるから、
まともでない(古い)コンパイラだとfor使うより遙かに速く動作する

そういう意味では書く人の習慣の影響が強いが
0059デフォルトの名無しさん2008/05/15(木) 22:04:53
だんだんコンパイル速度が遅くなってきたので、参照箇所の
多いクラスにPimplを導入しようかと思ってるのですが、Pimplに
すると問題のあるケースなんてのもあるんでしょうか?
0060デフォルトの名無しさん2008/05/15(木) 22:11:37
>>56
>memcpy(q,p,(n+1)*sizeof(*p));
29文字
0061デフォルトの名無しさん2008/05/15(木) 22:27:54
std::copy(p,p+n+1,q);
21文字
0062デフォルトの名無しさん2008/05/15(木) 22:45:30
>>59
pimplを経由することによる性能上のオーバーヘッド
0063デフォルトの名無しさん2008/05/15(木) 23:02:23
>>59
メモリ確保のオーバーヘッドと、メモリ確保に失敗する可能性の増加。
0064デフォルトの名無しさん2008/05/15(木) 23:23:16
>>62,63
なるほど。速度が重要な物や大量に生成される物には
避けた方が良さそうなんですね。
0065デフォルトの名無しさん2008/05/15(木) 23:24:01
>>59
仮にPimplによる問題が出ても、
大した手間無く対処出来るから気にする必要無いよ。
0066デフォルトの名無しさん2008/05/15(木) 23:36:11
>>59
相互参照の必要な場合が多いとソースが汚く見えるようになる。
0067デフォルトの名無しさん2008/05/16(金) 02:57:03
すいません、質問お願いします。
独習Cで勉強しているのですが、月での実効体重だす問題で関数を作ったのですが
float moon(void)
{
float weight;

printf("体重を入力してください:");
scanf("%f",&weight);
return weight*(17/100);
}

という関数を作った時に
「return weight*17/100」や「return weight*0.17」時は正しい値を返してくれるのですが、
自分が分かりやすいように式を()で囲うと正しい値を返してくれずに0.00000という値が返ってきます。
理由がわからないのですが、どなたか分かる方教えて下さい。
0068デフォルトの名無しさん2008/05/16(金) 02:59:30
すいません、>>67ですが、環境はDev−C++です。
0069デフォルトの名無しさん2008/05/16(金) 03:01:40
intをintで割ったときでも値はint。つまり(17/100)は小数点以下が切り捨てられて0になる。
(17.0/100)とかならOK
0070デフォルトの名無しさん2008/05/16(金) 03:04:13
>>67
17と100が整数だから、17 / 100の結果も整数(切り捨てで0)になってしまう。

weight * 17 / 100と書いたときには、(weight * 17) / 100と扱われ、
weight * 17がfloat型で結果を返し、それに整数100を掛けても
やっぱりfloat型になるのでうまくいくという具合。

逆にいえば、17などをfloat型にすればいいわけで、
return weight * (17.0f / 100.0f);とすればうまくいく。
0071デフォルトの名無しさん2008/05/16(金) 03:09:58
>>69
>>70
なるほど、型が大きいほうに合わせられるっていうのは数値だけの計算にも当てはまるんですね。
変数だけしかそういう風にならないと勘違いしていました。
非常に分かりやすい説明ありがとうございました。勉強になりました。
0072デフォルトの名無しさん2008/05/16(金) 11:46:56
直書きの数値にも型はあるんだぞ
0073デフォルトの名無しさん2008/05/16(金) 11:58:44
リテラルと言いましょう
0074デフォルトの名無しさん2008/05/16(金) 13:09:38
すまん、用語には疎いもんで・・・
0075デフォルトの名無しさん2008/05/16(金) 20:39:22
>>20

>・templateクラスにして継承関係を逆にする
>  ※ template<class T> class base : T {};

これ、よく分からないので具体例あげてくれるとありがたい。
0076デフォルトの名無しさん2008/05/17(土) 03:21:50
struct A {
A() { f(); }
virtual void f() = 0;
};

struct B {
virtual void f(){}
};


を


template<class T>
struct X : T {
X() { f(); }
};

struct Y {
void f() {}
};

typedef X<Y> Z;
0077デフォルトの名無しさん2008/05/17(土) 03:22:49
修正
> X() { f(); }
X() { T::f(); }
0078デフォルトの名無しさん2008/05/17(土) 09:58:03
質問です
先日基底クラスのデストラクタを仮想にし忘れ、メモリーリークというお約束のミスをやってしまいました。
この手のミスを無くしたいのですが、warningを出させる方法や、チェックツールなどはないでしょうか?
環境はVS6.0です。

仮想関数テーブルへのアクセスによるオーバーヘッドは現状気にしていないので、全てのクラス関数を仮想にしたいのですが、たまにつけわすれてしまうのです。
0079デフォルトの名無しさん2008/05/17(土) 10:04:15
初心者です。
C++を学ぼうと思ってるんですが良い参考書orWebページはありますか?
0080752008/05/17(土) 10:09:49
>>76-77

ありがとう。
ただこの方法だと元々の継承関係が失われないかい?
(76はミスタイプと思うが、元々はstruct A : B)

質問者は継承関係は維持したいと思うけど。
0081752008/05/17(土) 10:13:13
>>80

というか継承と同じことをテンプレートで実現するってことかな。あってる?
0082デフォルトの名無しさん2008/05/17(土) 13:28:04
>>78
「メモリリーク 検出」とかでググれば解説してるサイトがいっぱいでてくる
0083デフォルトの名無しさん2008/05/17(土) 13:55:08
>>78
デストラクタを仮想にした基底クラスを作って、クラスを作るときに必ずそれを派生して使うようにすれば忘れることはない。
0084デフォルトの名無しさん2008/05/17(土) 13:57:15
>>83
それを忘れないようにするためって話じゃないのか?w
0085デフォルトの名無しさん2008/05/17(土) 13:58:33
>>83
デストラクタの話ね。
0086デフォルトの名無しさん2008/05/17(土) 14:43:18
>>83はルート基底クラス(C#とかのObject)を用意することで、
個別にvirtualを書かなくて済むようにした方が良い、って意味なのでは?

でもそしたら今度は、それ継承するのを忘れない方法は?
って話になりそうだけど。
0087デフォルトの名無しさん2008/05/17(土) 14:46:51
クラスを定義するときに専用のマクロを使うことにするとか
0088デフォルトの名無しさん2008/05/17(土) 14:57:06
>>87
それを忘れないようにするためって話じゃないのか?w
0089デフォルトの名無しさん2008/05/17(土) 15:02:42
>>88
忘れにくさという点で、
>>78より>83
それより>>87
と良くなっているように見えるけど。
0090デフォルトの名無しさん2008/05/17(土) 15:10:27
コピペ煽りに律儀に答えなくても
0091デフォルトの名無しさん2008/05/17(土) 15:42:28
class NewClass : public Object
の : public Objectを書かなかったらやっぱりバグるわけだしなー
それじゃ意味ないだろう

継承しなければコンパイルエラーになるようにできるなら、別だが。
0092デフォルトの名無しさん2008/05/17(土) 16:13:22
なんでループしてんの?
0093デフォルトの名無しさん2008/05/17(土) 16:19:14
struct Object{virtual ~Object(){};};
#define STD_STRUCT(NAME) struct NAME : public virtual Object
#define STD_CLASS(NAME) class NAME : public virtual Object

STD_CLASS(ClassA) {
public:
  ~ClassA(){std::cout << "~ClassA" << std::endl;}
};

STD_CLASS(ClassB), public ClassA {
public:
  ~ClassB(){std::cout << "~ClassB" << std::endl;}
};

void f()
{
  ClassA* p = new ClassB();
  delete p;
}
0094デフォルトの名無しさん2008/05/17(土) 16:27:10
そしてそのマクロを使うのをつい忘れるわけですね、わかります
0095デフォルトの名無しさん2008/05/17(土) 16:30:03
>>94

>>89

5レス前すら読めない人はこのスレに必要ありませんよ
0096デフォルトの名無しさん2008/05/17(土) 16:31:46
いや、お前ら質問者の意図無視しすぎだろw
0097デフォルトの名無しさん2008/05/17(土) 16:33:46
ツールでなんとかしたいと言ってる人間に、忘れないようにマクロを使いましょうってどんな返事なんだ
俺は必要としたことないから知らんが、書式チェックツールくらいないのか?
0098デフォルトの名無しさん2008/05/17(土) 16:36:19
virtual忘れをチェックしてくれるツールくらい自分作ればいいんじゃね
デストラクタは先頭に ~ が付いててわかりやすいから、
その前にvirtualが付いてるかどうかくらい簡単に判定できそう
そもそもデストラクタを書いてない場合は役に立たないが・・・
0099デフォルトの名無しさん2008/05/17(土) 16:38:42
>>96
>>78を読む限り、まずミスを無くしたい、という目的があって、
その方法として警告、チェックツール「など」、
と手段の例を挙げているので、
同じく、ミスを無くす/減らす方法を書いてるレスが
意図を無視してるようには見えないけど?
0100デフォルトの名無しさん2008/05/17(土) 17:06:19
とりあえず、抽象型へのアップキャストは極力控えて、
総称型プログラミングを覚えた方がいいと思った。
0101デフォルトの名無しさん2008/05/17(土) 17:08:30
>>100
実行時ポリモーフィズムが必要な場合はどうするの。
0102デフォルトの名無しさん2008/05/17(土) 17:10:55
だから極力控えて、って・・・。
0103デフォルトの名無しさん2008/05/17(土) 17:31:36
静的な方が安全というのは分かるが、
export のない C++ でジェネリックばっかやってると
コンパイルが重くて現実的じゃない事も。
0104デフォルトの名無しさん2008/05/17(土) 21:16:08
>>98
そしてそのツールでチェックするのをつい忘れるわけですね、わかります。
0105デフォルトの名無しさん2008/05/17(土) 22:34:11
>>104
make使うならMakefileに組み込めばおk。
総合環境なら・・・ カスタムビルドステップ?
0106デフォルトの名無しさん2008/05/17(土) 22:42:35
>>104
最悪、考え方としてはおかしくなったときにチェックすればいいわけだし。
0107デフォルトの名無しさん2008/05/17(土) 23:08:54
あれ?ちょっとずれるが
なんかの統合環境で、virtualな関数をオーバーライドする時にvirtualつけておかないとワーニング出すって設定できたよな?
これはvirtualですよー、わかってますかー?って意味合いで
■ このスレッドは過去ログ倉庫に格納されています