【初心者歓迎】C/C++室 Ver.102【環境依存OK】
■ このスレッドは過去ログ倉庫に格納されています
エスケープシーケンスやWin32APIなどの環境依存なものもOK
そのような質問は必ず環境を書きましょう
半角空白やタブでのインデントはスレに貼ると無くなります
コードを貼れる所
http://codepad.org/
https://ideone.com/
前スレ
【初心者歓迎】C/C++室 Ver.101【環境依存OK】
https://mevius.5ch.net/test/read.cgi/tech/1500329247/ void Show(const IntArray& array){
...
}
というような関数内で、 array の const メンバ関数ではないメンバ変数を変更しないメンバ関数を
使っているとコンパイルエラーになりますが、それはなぜでしょうか?
コンパイラーはarrayのメンバ関数がメンバ変数を変更していないことはソースコードから
分かるのではないでしょうか?
そういうチェックをするコンパイラを作るのは難しいからということでしょうか? const メンバ関数の中でメンバ変数の内容を変更しているとコンパイルエラーになります。
ということはどのみちメンバ変数を変更しているかどうかはチェック可能ということですよね? void Show(IntArray& const array) >>449
コンパイル単位を越えたらチェックするのは難しいし言語の壁を越えたら不可能に近いから
中途半端な事をするくらいならconst明示されてるかという線引きの方が分かり易い >>449
難しいというか不可能だからですよ
呼び出す関数はまだコンパイルされてないかもしれないしまだソースコードもないかもしれない >>449
メンバ変数を変更しないなら素直にメンバ関数にconst付けれや >>449-450 の質問者は、分割コンパイルにまだ慣れてないと思えるなぁ。
ソースファイルを分けてみればピンと来るかと。
片方をソースなしのオブジェクトやライブラリにしないとダメかな。 C#のフォームからオフィスを立ち上げ、オフィスを終了したら立ち上げたフォームに
戻るようにするにはどうした出来ますか? >>457
COM使えばできるけど、スレタイも読めないお前にできるかどうかはわからん そんなことは当たり前ですね。その方法が説明できますか? C#のことはC#のスレッドで尋ねればいいでしょ、てお話。
C/C++のスレッドに質問を持ち込むより確実で早いと思うよ。 あ、ごめん。++が#に見えた。でも普通は++を#に書き間違ったんだろうと判断すると
思うが。 ところでC++のフォームからオフィスを立ち上げ、オフィスを終了したら立ち上げたフォームに
戻るようにするにはどうした出来ますか? >>463
CreateProcess() win32API スレへgo >>464
it is conditional on your ability, although its mean applying in the case of a usual Japanese. main関数の中でstaticを使う意味は何でしょうか?
ロベールの本のpp.318-319にそのような例が出てきて意味不明です。 ロベールの本を持ってないんで、適切な回答じゃないかもしれんが。
main() 関数の中でstatic変数を使う意味といえば、
単純型の初期化の処理時間を回避したいか、
セクション(変数のメモリ配置)の説明のためか、
「staticなインスタンスのコンストラクタはmain()より前に実行される」
ていう話の前フリかなぁ。 >>472
ローカル変数に static 変数が付いていた場合は最初に通過したときに初期化されるルール。
(コンストラクタもそのときに走る。)
これは C のときから変わってないよ。 普通に考えると、
単にスコープをローカルにしたいってのがまず考えられる >>473
横からだけど訂正乙
初心者が読んで間違えて覚えるので、初心者スレでは嘘を書かないように特に気をつける必要ある >>474
mainの中だから意味無い
っつーかstaticは二つの意味があって全然別物
スコープと性的と混ぜるな危険 >>474は
関数内でstatic変数を使うのは静的変数のスコープを関数ローカルにしたいからでは、
というごく当たり前の文意だろ普通に読むと。
どう読むと
関数内だからファイルローカルの話とか関係ない!勘違いするな!となるんだよ
自分以外は文法もセマンティックもろくに知らないという前提はやめるべき >>470
スコープはmaim( )内にしたいけどスタックは使いたくないってケースかな >>470
ウェブ版をざっと探してみたら main 内で satatic 変数を使ってるのはこれだけだったんだけど、
これのことか?
http://www7b.biglobe.ne.jp/~robe/cpphtml/html02/cpp02037.html 関数スコープのstaticなクラス・インスタンスのコンストラクタは
main()以前でなく、最初にその部分が実行されたときに初期化されるんだっけか。
static なら一律にmain()の前、基本型や単純な構造体のstaticはロード時に初期化、
だと勘違いしていた。
訂正してくれてありがとう。そして間違ったことを書いてすまぬ。 初期化が固定データのメモリコピーで済むものはロード時に初期化するコンパイラが普通 >>480
ありがとうございます。本とは内容が違うようです。
int main() {
static const double ARRAY1[] = {1, 2, 3, -1};
static const double ARRAY2[] = {0.5, 1.5, ,-1};
static const double ARRAY3[] = {-1};
static const double* const ARRAY[] = {ARRAY1, ARRAY2, ARRAY3};
…
}
というコードが該当箇所です。 staticを付けなければスタックに確保されるかもしれない。その場合、どうしても遅くなる。 >>485
でも、速さがどうとかいうことについては何も書いていないんです。
staticを付けていることについては何の説明もありません。 >>486
>>485はきちんとした回答だと思うよ。
配列が大きくなれば顕著になる。
「その本に書かれていないから」と拒絶するのは憲法に基づいて自由だけど 定数だからstatic constにした
というだけのことでそれ以上の意味はないと思うが その変数をコンパイル時点で確定しようとしている。
ローディング時間も早くなる >>487
だぶんだけど、 >>486 が言おうとしているのは「>>485 だとしたら入門書としては不親切だよね!」って話じゃねーの。 >>484
ROMとRAMに別れてる環境、
つまりほとんどの小規模な組み込み環境だと
static const は通常ROMに配置される
要するにRAMの節約
速度は逆にRAMの方が速いのが普通 クラスの定義をヘッダファイルに書くときに、
privateなメンバまで書くのはなぜですか?
必要ないように思います。 >>484
みなさん、ありがとうございました。
速度について気にしているのなら、ロベールにはそう書いてほしかったです。
例では、非常に小さな配列ですから速度について気にしていることは読み取りにくい
ように思います。
>>488
定数だから const にしたというのなら分かるのですが、なぜstaticをつけるのでしょうか? >>492
private なメンバはむしろ、クラスのメンバ関数を実装する .cpp ファイルに書いた方がいいように思います。 >>494
pimplイディオムで、クラス詳細を隠蔽できるよ。 >>493
あの部分では特別に速度を意識した記述ではなく普通に意識する程度の事だから一々説明されないということではないかな
速度や使用メモリを気にするのはCやC++プログラマの癖または習慣みたいなもので特にロベールみたいな昔の人は体に染み付いているだろうからね >>493
今回はたまたまmainであり、
たまたま小さなデータだったというだけで、
より汎用性の高いコードにするのはプログラミングの基本
staticを付けるメリットは
・データ構造の初期化が1回(ROMだと0回)で済む
・スタックを浪費しない
・関数を抜けてもデータが保持される
・番地が固定
デメリットは
・関数を通らなくても初期化される
・関数外でもメモリを使う 一番重要なのは>>491
PCプログラムしかやらない人は知らないだろうけど test2の形だと上手く動作しないのですが何故でしょうか
環境はvc6とstlport521です
void test1(const char* cstr, ...) {
char buf[1024];
va_list args;
va_start(args, cstr);
vsprintf(buf, cstr, args);
va_end(args);
printf(buf);
}
void test2(std::string str, ...) {
const char* cstr = str.c_str();
char buf[1024];
va_list args;
va_start(args, cstr);
vsprintf(buf, cstr, args);
va_end(args);
printf(buf);
}
void main() {
test1("hello1 %d\n", 123);
test2("hello2 %d\n", 123);
}
//結果
//hello1 123
//hello2 1819043176 引数を std::string &str, ... にすればなおる 引数を参照とポインタでも試してみましたが結果は変わらなかったです
void test3(std::string& str, ...) {
const char* cstr = str.c_str();
・・・
void test4(std::string* str, ...) {
const char* cstr = str->c_str();
・・・
void main() {
・・・
std::string str3("hello3 %d\n");
test3(str3, 123);
std::string str4("hello4 %d\n");
test4(&str4, 123);
}
//結果
//hello1 123
//hello2 1819043176
//hello3 1819043176
//hello4 1819043176 va_start(args, cstr);
なんでcstr? ああなんとなく意味が分かってきました
va_startはマクロであってcstrの部分は引数の変数名が指定されなければならないということですかね こういうコードにすると期待した動作をするようになりました
ありがとうございました
void test5(std::string str, ...) {
char buf[1024];
va_list args;
va_start(args, str);
vsprintf(buf, str.c_str(), args);
va_end(args);
printf(buf);
}
void main() {
・・・
test5("hello5 %d\n", 123);
}
//結果
//hello1 123
//hello2 1819043176
//hello3 1819043176
//hello4 1819043176
//hello5 123 ついでに言うと va_start の第二引数については仕様上結構な制限、
各 argument に課される制約と同じ制約がある
配列はダメ、参照はダメ、基本型が格上げされる型との互換性が必要、など
最後のはクラスオブジェクトや float はダメということ
仕様として結果が不定なだけで違反してもエラーにはならないし
意図した通りに動くことも多い
詳しくは default argument promotions va_start
で検索 va_listとC++は、相性が合わないんだよな。呼び出し側でc_str()するとか。 特に強い理由がなければ variadic template を使った方が安全だし簡単に書ける。
template<class... T>
void test6(std::string str, T... args) {
char buf[1024];
std::sprintf(buf, str.c_str(), args...);
std::printf(buf);
} えー、可変長引数の例にしただけなので、そんなどうでもいいとこを言われても困るよ。 そう言うところにしか突っ込めない雑魚の相手するなよ... >>511
なんでbufに一旦書いてるの?
直接printfじゃだめなん? 普通はね
クソコテがコードサイズ、互換性、実行速度など
全て犠牲にしてもテンプレートを使いたかったみたい va_start の第2引数の型の制限を知らなくてもor気にしなくても良いように
C++ らしく va_start 使わない例を出したんだろ…
と書いてはみたが、
そういう意図が通じるわけないか
通じる人は最初からわかってるもんな そもそも何でbufにって質問は
コメント元の>>507にすべきだろ こんな辺境ですらイキリ散らすなんて呆れる他ありませんわ 危険てんこ盛りなコードの危険性が低い部分をなおしてどうすんの?アホなの?
オナニーは隠れてやれ c++ スレで variadic template 紹介されてこの反応 >>526
危険性が高いかどうかは重要じゃなくて、話題のテーマに近いかどうかだろ。
本題に関係ないところなんてどうでもいいじゃないの。 >>501とvariadic templateは関係ないわけだが const double const ARRAY[] = { 3, -1 };
const double ARRAY[] = { 3, -1 };
の違いを教えてください。 ポインタ変数なら
・変数も指し先も書き換えられない
・変数は書き換え可能。 指し先は書き換えられない
のパターンだけど
対象が配列の場合、元々変数の書き換えができないから同じ意味じゃないかと >>531
> const double const ARRAY[] = { 3, -1 };
コンパイルエラーにならないんだっけ? >>532
ありがとうございました。
>>533
Visual Studioではコンパイルエラーになりません。 const double const a[];
は
const double a[];
と同じ意味
const const double const const a[];
なんて書いてもいいし
double const a[];
と書いてもいい
const typename と typename const と同じ
しかもconstはいくつ書いてもいい Win32のBOOL型を返す関数を複数回呼んで、
すべて成功したときのみTRUEを返したいのですが
(途中で失敗しても関数自体はすべて呼んでおく)、
BOOL Test()
{
BOOL bResult = TRUE;
bResult &= Api(...);
bResult &= Api(...);
bResult &= Api(...);
return bResult;
}
と書いてとりあえず動くのですが、よく考えたら&=はビット演算だし、
Win32のBOOL関数は成功時にTRUEを返すとは書いていないので、
例えば関数が成功時に2を返すパターンがあったら、
すべて成功しても戻り値はFALSEになるのではと思っています。
この場合、
bResult = Api(...) && bResult;
bResult = Api(...) && bResult;
bResult = Api(...) && bResult;
みたいな書き方をするしかないのでしょうか。 result &= !!api(...);
という風に!!を使うのも zero, non zero を false/true に正規化するイディオムだけど、
何にしても見た目は汚いと思う
文字数は増えるがif文を使って
if (!api()) result=false;
の方が可読性高いかもしれない >>539
成功した回数をカウントして呼び出す関数が3つなら3でTRUEにするかな
BOOL Test()
{
int count = 0;
if(Api() != FALSE) count++;
if(Api() != FALSE) count++;
if(Api() != FALSE) count++;
if(count == 3) return TRUE;
} 結果を std::vector にでもまとめておいて、 std::all_of で全てがFALSEでないことを確認するとか。 >>539
> bResult = Api(...) && bResult;
> bResult = Api(...) && bResult;
> bResult = Api(...) && bResult;
これでいいと思う
>>541
3個位ならいいけどたくさんになると数え間違いとかやらかしそう 普通に&で繋げてしまえば。
return Api()&Api()&Api()...; みなさんご意見ありがとうございます。
例を簡略化しすぎてしまいましたが、処理は状況によって分かれるため、
常に同じ関数が3回というわけではありませんでした。
失礼しました。
bResult = Api(...) && bResult;
の書き方自体は、そこまで汚いわけではないのですね。
同じような書き方をしているソースも、検索してみたら出てきました。
個人的には、
bResult &&= Api(...);
のような記述ができるとありがたかったです。 >>547
こういう手段もあるぞ。
bResult *= Api(...);
一度 0 になったら何をかけても 0 だ。 ■ このスレッドは過去ログ倉庫に格納されています