C++相談室 part159

■ このスレッドは過去ログ倉庫に格納されています
1デフォルトの名無しさん
垢版 |
2022/02/19(土) 11:56:42.14ID:kSnJ/KwP
前スレ
C++相談室 part158
https://mevius.5ch.net/test/read.cgi/tech/1636969758/
2022/02/26(土) 23:27:30.26ID:w5NWCXyu
固定ならconstexpr使おうや
2022/02/26(土) 23:36:20.44ID:I1qWxMaG
>>257
文字通りconstにしたいのですヽ(`ー´)ノ
引数に再代入するのはガイジのやることなので(>>251

で関数定義でそうしたら、作業性のためにそれをコピペして極力弄らずにヘッダファイルにするから
宣言においても値渡しの引数にもconstが付くのでつ∀`;)
2022/02/26(土) 23:43:30.97ID:w5NWCXyu
まあ非参照型でconstついてなかったらとりあえず
ひょっとして関数内で書き換えられるんかと疑ってかかるよね
2022/02/26(土) 23:44:54.89ID:I1qWxMaG
>>232
IPAコーディング左方ガイド[C++言語編] (p.120)
https://www.ipa.go.jp/files/000055043.pdf
>M1.11.1 参照しかしない領域は、const 型であることを示
>す宣言を行う。
(中略)
>参照するだけで変更しない変数を const 型で宣言することで、その変数を変更しないことを明
>示できる。また、処理系の最適化処理でオブジェクトサイズが小さくなる可能性もある。この
>ため、参照しかしない変数は const 型にする。

やそうや;;;
具体的には知らん
2022/02/26(土) 23:45:14.56ID:nPeFYJEF
引数に再代入するかどうかは呼び出し側の与り知らぬところなんで
それを公開インターフェースに乗せるのはどうかなぁ。
2022/02/26(土) 23:45:57.76ID:BX4iLvdt
Rustだと値渡しだけでなく参照渡しも無指定デフォルト時は書き換え不能だよな
書き換えが起こる関数へは指定して可変参照を渡す
2022/02/26(土) 23:48:32.78ID:UUNvHcAJ
どこぞの馬の骨とも知れないIT後進国ジャップが言う事よりも天下のGoogle様のコーディング規約を真似るほうが無難だぞ
そしてGoogleのコーディング規約によると「可能な限りconst付けまくれ」との事
実際にGoogleが公開してるライブラリはCにしろC++にしろ関数の引数から大体const付いてる、ポインタは勿論constバーガーで
2022/02/26(土) 23:50:44.52ID:I1qWxMaG
>>262
あずかり知らぬことならどうでもいいんじゃ……
コピペした後手作業でconstを消すとかアフォらしい漏れクラスの天才の単金は高いからな
やっぱ作る方の作業性優先で、

記憶モードだがVC++のインテリセンスは値渡しのconstは除去して提示してくれるはず……
2022/02/26(土) 23:58:24.50ID:nPeFYJEF
でもconst書く方の手間は惜しまないんだ
2022/02/26(土) 23:58:37.20ID:Cf/OFvAp
> 処理系の最適化処理でオブジェクトサイズが小さくなる可能性もある。
> int bar(const int x,

これをどうやって小さくするんだ? そもそもconstの値渡しの話だよな。
2022/02/27(日) 00:02:08.66ID:/TAxLK2K
>>264
へぇ〜知らなかったわこれ
流石ゴーグル様やで
2022/02/27(日) 00:02:10.22ID:o7kRBzLD
引数で明示的に書き換え禁止にしたいということはポインタ渡しか参照渡しだよな。
アドレスしか渡してないのに最適化でオブジェクトサイズが小さくなるというのはどういう意味だろう?
2022/02/27(日) 00:05:12.18ID:o7kRBzLD
> 「可能な限りconst付けまくれ」
自分で設計、コーディングができなくてオープンソースをパクる側の意見だろう。
あくまでパクりすぎて訴えられて負けるググルくんの意見。
2022/02/27(日) 00:07:37.55ID:KWP91+7v
char*ならアドレス渡すより実値渡す方がサイズ小さくて済むとかじゃない?知らんけどね
2022/02/27(日) 00:14:47.59ID:/TAxLK2K
>>269
値渡しだとしても関数内で決して書き換えませんよって意思表示でconst付けるんだわ
使う側はどうでもいいのかも知れないけど少なくてもメンテ側はその方が楽
2022/02/27(日) 00:39:11.54ID:GNkMbU6V
実質in宣言だよね
2022/02/27(日) 05:41:24.49ID:+yReYAPt
まだ馬鹿がconst不要とかアホなこと言って荒らしてるのか・・・
275デフォルトの名無しさん
垢版 |
2022/02/27(日) 07:45:11.01ID:hjaMvOv0
もういっそのこと、constをメンバ関数宣言のデフォルトにして、volatileキーワードをメンバ関数宣言にそえないとメンバ変数の値を変更できないような仕様変更をしたほうがいいくらいだよ
2022/02/27(日) 07:54:46.50ID:XiobTp3y
ラムダ式の値キャプチャはデフォでconstだね
constつけたくないときはmutable
2022/02/27(日) 13:50:59.05ID:i/FBvdzu
勝手な憶測だけどconst付けると即値埋め込み以外にもどの変数をレジスタに入れるかって辺りの最適化が効きやすくなりそうな気はする
278デフォルトの名無しさん
垢版 |
2022/02/27(日) 14:21:10.71ID:ai7feBss
class ClassA {
public:
int x, y;
ClassA(int n1, int n2) { x = n1, y = n2; }
virtual void VirFunc() = 0;
};

class ClassB :public ClassA {
public:
ClassB(int n1 = 0, int n2 = 0) :ClassA(n1, n2) { ; }
void VirFunc() { cout << "Disp1:x+y=" << x + y << std::endl; }
void Dummy() { ; }
};
void check(ClassA* obj)
{
if (typeid(*obj) == typeid(ClassB)) {
static_cast<ClassB*>(obj)->VirFunc();
}
}
int main()
{
ClassB objB(10, 20);
check(&objB);
}
279デフォルトの名無しさん
垢版 |
2022/02/27(日) 14:21:28.24ID:ai7feBss
クラスの継承やtyoeidで今躓いています。
objにclassBがなんで代入出来てなんでキャストできるのかわかりません。
check関数の中の引数、ClassAのポインタにClassBで実体化したオブジェクトのアドレスを入れると言うことは
継承した部分だけを見ることで同じ型として見ているのですか?
だとしたら派生先のクラスでできたメンバ?がどうなるんだろうと言うのもわからなかったりはします。
280デフォルトの名無しさん
垢版 |
2022/02/27(日) 14:22:00.29ID:ai7feBss
すみませんコードってどう上げれば良いんでしたっけ?
2022/02/27(日) 14:34:30.92ID:57HjD/n9
const の必要性ってこういうときにあると思ってる

struct T { int x; int y; T(int _x,int _y):x(_x),y(_y){}};
int test1(T &a){ return a.x*a.y;}
int test2(const T &a){ return a.x*a.y;}
int main() {
T a(10,5);
printf("%d",test1(a));//OK
printf("%d",test1(T(5,4)));//エラー
printf("%d",test2(a)); //OK
printf("%d",test2(T(4,6)));//OK
}
2022/02/27(日) 14:38:16.26ID:gvx2nAxT
>>279
想像のとおりです
なのでメンバーが減るようなキャストはまずい
283デフォルトの名無しさん
垢版 |
2022/02/27(日) 14:51:04.74ID:ai7feBss
>>282
ありがとうございます。
アップキャストダウンキャストも関わっていたのですね
すぐにはわかりませんでした。
たとえばなんですけど派生クラスBは基本クラスAに別の名前を付けてかつBで新たに
加えられたメンバはBから紐づけられていて、これらをセットにして見やすくしたものが
派生クラスBになると言う感じなのです?
2022/02/27(日) 15:01:31.40ID:ftSqTRxL
派生クラスのオブジェクトには基底クラスのオブジェクトが含まれる。
派生クラスの一部であるようなオブジェクト (基底やデータメンバ) をサブオブジェクトという。
285デフォルトの名無しさん
垢版 |
2022/02/27(日) 16:18:03.61ID:ai7feBss
>>284
ありがとうございます。
サブオブジェクトがサブオブジェクトと言われることにつながるのですね。
2022/02/27(日) 16:44:15.33ID:+yReYAPt
ダウンキャストは危険で、本来無条件にやっていいものではない
なので実行時型チェックをして使っている今回は問題ないだけ

なお、static_cast<ClassB*>(obj)->VirFunc()は最近のコンパイラ(gcc11.2)だと
最適化なし時はClassA*として仮想関数呼び出しと同じ方法で呼び出す
最適化あり時はvtableがClassB::VirtFunc()かどうか確認してインライン展開したものが実行される
(万一確認失敗したら仮想関数呼び出しと同じ方法で呼び出す)
2022/02/27(日) 17:38:03.37ID:HuUTW9GQ
ダウンキャストをするならstatic_castではなくdynamic_castを使うべき。
見ているobjの実体がclassBじゃないなら失敗してnullptrを返してくれる。

そもそもダウンキャストが必要になること自体良い設計ではないが

auto* pb=dynamic_cast<classB*>(pobj);
if(pb){
pb->...;
}
2022/02/27(日) 17:46:47.65ID:NpJPdMJB
「キャストはなるべくするな、特にdynamicはコストが高い」と古文書にもあった
2022/02/27(日) 17:54:22.89ID:+yReYAPt
今回はそれをtypeidでやりたかったんでしょ
2022/02/27(日) 18:02:07.86ID:HfpUvsK0
ダイナミックダイクマ
291デフォルトの名無しさん
垢版 |
2022/02/27(日) 20:42:58.79ID:ai7feBss
なんかC++が気になるので実践的な情報でもなんでもありがたいです。
C++で食べてる人と話したこともないし・・・
2022/02/27(日) 20:45:27.70ID:NpJPdMJB
古文書には「#defineではなくconst,enum,inlineを使うといい」ってあるよ
2022/02/27(日) 20:47:31.05ID:nGlHhzSe
死海文書では「constexpr, enum struct, enum class」を使うことで難を逃れたと書いてある
2022/02/27(日) 20:56:43.39ID:o7kRBzLD
const使えば分かる。#defineのほうがやっぱり便利だわ。
2022/02/27(日) 21:21:58.39ID:Xl3wWN+O
C++のenumは機能が弱いからなあ
Rustのenumみたいに任意の型の変数値を格納できるようにしてほしい
2022/02/27(日) 21:31:32.92ID:nXG/aSfD
>>275 >>276
その方針で全ての変数のデフォルトをC++のconst状態にしてしまったのがRustだね
代わりに値が変化する変数にだけミュータブル指定しないといけないけど
if-elseもループもブロックも値を返してくれるためほとんどの変数が変化しない
2022/02/27(日) 21:36:52.29ID:o7kRBzLD
char*やシンプルな構造体ならconst使うのはメリットあると思うが、
あれこれ機能が詰め込まれるクラスになると不便さ、面倒さのほうが際立つ。
多重継承並にハゲる原因になる。
2022/02/27(日) 22:28:50.95ID:hjaMvOv0
まーたしかにconst_castだらけになるかもしれないね
2022/02/27(日) 23:37:06.31ID:ftSqTRxL
const_cast を正しく使うのは難しい。
const なオブジェクトから const を剥がして書き換えるのは未定義。
数年前に LLVM が const 指定の情報を最適化に活用する方向に舵を切ったというニュースもあった。
const ではないオブジェクトに対して const なポインタや参照を経由している場合には
const を外して書き換えるのは許されるはずだが、
それが必要になるようだと設計を見直したほうがいい。

現在のコンパイラは賢くて、 const 指定をしてなくても書き換えられる可能性がないことを見抜いて最適化することも多いんで、
const の指定自体は最適化にはそれほど寄与しないよ。
ただ、 const を前提とした設計はコンパイラにとって最適化しやすい構造である可能性はある。

@ const を前提にした設計にできるもんならしたほうがいい
A そうできないなら無理に const を付けないほうがいい (後で場当たり的に const_cast で const をはがすとどこかで間違う)
2022/02/27(日) 23:43:44.46ID:o7kRBzLD
書き換えないコードの場合はどういう最適化がされるのかを知りたいのだが。
2022/02/27(日) 23:51:40.12ID:HuUTW9GQ
getterにlockを仕込む場合にgetterをconstにするべきかどうか悩む
const扱いにしてmutexに関してだけconstをはがすべきなのか

class C{
std::mutex _mtx;
int _a;
public:
int get_a(){
std::lock_guard lk(_mtx);
return _a;
}
void set_a(int a);
};
2022/02/28(月) 00:43:20.93ID:7GK6w4Z4
>>301
俺ならgetterにはconst付けてmutexメンバ変数にはmutable付けるね。
2022/02/28(月) 00:54:54.67ID:R6BwoFXD
>>301
俺も >>302 には賛成。
mutex はあくまでも内部的な実装の都合であって、
それを mutable にしてもクラスの logical constness は維持されると判断する。
2022/02/28(月) 01:18:45.25ID:EeqSDih1
>>300
だからお前は何を調べたとずっと聞いてるんだがw
2022/02/28(月) 01:22:01.28ID:LWo9z6at
言い出した本人が逃げ出して答えないし、誰もはっきりと答えないんだからウソなんじゃね?
2022/02/28(月) 01:25:22.84ID:EeqSDih1
状況に依るけどmutableにするなら俺はunique_ptrとかにするかもしれない
2022/02/28(月) 01:42:21.31ID:EeqSDih1
>>305
言い出した本人はいるし、「お前は何を調べたとずっと聞いてる」のにしかも何度も聞いてるのに答えない=お前が逃げ続けてるからだろ?w
2022/02/28(月) 01:47:08.01ID:LWo9z6at
本人いたのか。自分で言い出したはいいが実はさっぱり分からないって感じか。
それはそれで仕方ない。発狂してたら余計にやっぱりウソなんだ〜ってなるだけだぞ。
2022/02/28(月) 01:50:37.25ID:EeqSDih1
もう寝るけど、お前がただただ煽りながら発狂しちゃってる間も、毎日何某か書いてるんだがw
いつになったらお前がどこまで何を調べたのか詳細に説明してくれるのか心待ちにしてるよw
2022/02/28(月) 01:50:44.99ID:h02lB8BP
>>302 >>303
ありがとうございます

なるほどフィールド側でconst扱いしないモードを初めから指定すればいいのか...
2022/02/28(月) 01:54:51.97ID:LWo9z6at
>>309
やっぱりウソなのか。散々暴れといてしょうもない奴だな、おまえ。
2022/02/28(月) 01:56:18.18ID:h02lB8BP
void f(const std::vector<int>&v){
for(size_t i=0; i!=v.size(); ++i)...
}

とかで
本来v.size()を毎回呼ばなきゃいけないけどconstだから1回呼ぶだけで十分って話とかじゃないの?

まあ俺も-O2コンパイル結果を読む気力はないからエアプ扱いしてもらって構わんが
2022/02/28(月) 02:03:13.46ID:/gADsoXI
constなんていつでもconst_castで引っぺがせるんだから、勝手に定数畳み込みとかは出来ないし
じゃあそういうのが無いのを検知すれば出来るだろというと、そんなに賢いならconst無しの変数でも同じ事が出来るはず
結論から言うとconstは最適化に何の影響も及ぼさない
畳み込ませたい定数はconstじゃなくenumか#defineで定義するのが正解
2022/02/28(月) 02:14:26.59ID:EeqSDih1
複数IDで暴れとるwwwww 朝までに具体的な事例を書いてねw
環境も明記されてないコンパイルも通ってないモノでは想像で言ってるだけってことになるよw
2022/02/28(月) 06:31:25.23ID:Zh+6zBsp
>>312
この例は毎回v.size()呼んで遅くなりうる
それは最初に1回一時変数に受ければ解決するがそれがconstかどうかはまずパフォーマンスに影響しないだろう

もっというとこれは生のfor文の欠陥でこれからはstd::views::iotaを使っていくべき理由の1つだと思う
2022/02/28(月) 06:47:54.89ID:EeqSDih1
>>315
その例はconstにしようがしなかろうがインライン展開されるので最適化結果に違いはないよ
そもそも最適化しやすくなると言ってるだけで、違いがあるとまでは言ってなかったんだけどw

>>314に書いたとおり、煽るだけ君は結局「想像で言ってるだけ」なんだなw
妄想はほどほどにしてくれw

最適化コードに違いがある例が以下。マクロの定義を空にすればconstなしのコードになる。
https://godbolt.org/z/YavYzrE3z
#define CONST const
template<typename T>
struct s {
T value;
operator T() CONST {return value;}
};
CONST s<int> a[] = {1,2,3,4,5};
template<typename T> T func() {
T r = 1;
for (int i = 0; i < sizeof(a)/sizeof(a[0]); ++i) {
r *= a[i];
}
return r;
}
int main() {
return func<double>();
}
2022/02/28(月) 07:29:26.73ID:Zh+6zBsp
>>316
俺はこの話題に関して初めて書き込んだ者だが
2022/02/28(月) 07:34:24.42ID:Od0J2fCm
>>316
都合の良い例にしすぎだろ
2022/02/28(月) 07:43:08.18ID:EeqSDih1
反証は1つで十分w 具体例の1つも書けない人は黙ってようねw
2022/02/28(月) 08:14:09.88ID:Od0J2fCm
ああすまん、変化しない例を出してるつもりだと思ってた
そんなコードでも変化したりするのね
2022/02/28(月) 10:21:52.93ID:ftLJb++c
古文書には#defineは良くないってあったけど今のC++ってその辺り改善されたんですか?
2022/02/28(月) 10:47:09.12ID:R6BwoFXD
>>321
ある程度は。
2022/02/28(月) 10:56:01.32ID:xzjNndYE
>>321
「その辺り」って何?
スコープとの相性が最悪って意味なら変わってないぞ
2022/02/28(月) 11:04:38.67ID:ftLJb++c
>>323
他所からパクってきたコードですが、#defineはそのまま書き換えるだけだから以下や

#define SIX 1 + 5
#define NINE 8 + 1

int main(void)
{
printf( "What you get if you multiply six by nine: %d\n", SIX * NINE );
return 0;
}

以下の関数の呼び出しなどで意図しない挙動になったりとかです

#define SquareMulti(x, y) x * x * y
SquareMulti(++a, b)
2022/02/28(月) 11:14:22.32ID:R6BwoFXD
>>324
その程度なら inline や constexpr を活用するのが今は良い作法
2022/02/28(月) 11:19:01.97ID:xzjNndYE
>>324
マクロに関してはそういう所は変わってない
餃子が言うようにマクロ以外の手段を使うというだけ
2022/02/28(月) 11:20:49.97ID:+7QZaSxQ
>>321
#defineじゃないとできない/面倒なパターンが減ったという意味ならある程度はマシになってる

<numeric>とか<source_location>とかconstexpr/constevalとか
2022/02/28(月) 11:24:50.52ID:s9ebK7Me
>>321
#付いてるから、基本プリプロセッサ文だかんな
2022/02/28(月) 11:39:25.77ID:42wjdHim
スコープ付きの#defineが欲しい時ってあるよね…w
2022/02/28(月) 12:09:06.26ID:EeqSDih1
ねーよw
2022/02/28(月) 12:16:38.60ID:WvOgTxGl
#define NAMESPACE namespase
#define NS ns

NAMESPACE NS{
void f();
}
void g(){
NS::f();
}

このへんのコードをプリプロセスの段階で正しく解釈するのは無理なのがね

#pragma defines(push)
みたいのが言語標準になればいけるか?
2022/02/28(月) 12:32:49.89ID:EeqSDih1
馬鹿の妄想は放置して、マクロでないと困る例
#include <iostream>
#define PRINT_LOCATION() (::std::cout << __FILE__ ":" << __LINE__ << ":" << __PRETTY_FUNCTION__ << "\n")
namespace hoge {
void func() {
PRINT_LOCATION();
}
}
using namespace std;
using namespace hoge;
int main() {
PRINT_LOCATION();
func();
return 0;
}
2022/02/28(月) 12:41:59.91ID:xzjNndYE
友達いなさそうだな
2022/02/28(月) 12:49:02.69ID:EeqSDih1
そんなこと気になっちゃう程度の馬鹿よりは多そうだけど、多けりゃいいってもんでもないと思うぞw
2022/02/28(月) 13:48:09.49ID:ftLJb++c
多くの回答ありがとうございます
やはり可能な限り#defineは避けた方が良さそうですね
ただ#defineでもできないことや、#defineにしかできないこともあるので変に毛嫌いせず勉強を進めてこうと思います
2022/02/28(月) 14:03:01.00ID:EeqSDih1
例外中の例外なので、毛嫌いして全く問題なく、勉強する必要も全くないw
2022/02/28(月) 15:55:04.33ID:Yx2Q2Rjy
Include Guard Macro以外の#defineは忘れてもいいと思う。
2022/02/28(月) 17:13:33.60ID:HhKI/yF6
ほんそれ
一生ソロプレイかつCにしがみつくつもりなら構わないけど
そうじゃないなら基本的に使わないべき遺物
2022/02/28(月) 20:11:29.53ID:Zh+6zBsp
ほぼ同じ演算子オーバーロードを延々と書く場合とかマクロでまとめていいと思うけどね
テンプレートではどうしようもないレベルのメタプログラミングの手段として未だに有効
340デフォルトの名無しさん
垢版 |
2022/02/28(月) 20:17:53.65ID:xrBOKM6i
むしろ、他言語にマクロ展開機能がないことが不満
2022/02/28(月) 20:19:01.14ID:EeqSDih1
そうなる仕組みもどうかと思うけど、必要悪として採用するケースが「あってもいい」という程度だよ
2022/02/28(月) 20:39:17.05ID:xzjNndYE
>>339
だよな

復号代入とかフルで揃えようとすると
毎回同じようなコードを延々書くからな
2022/02/28(月) 21:11:31.61ID:EeqSDih1
だよなじゃねーよw
本当にマクロでないとできないケースなのかすら怪しいw
2022/02/28(月) 21:21:08.91ID:TawWBZkT
>>339
テンプレートでできなくてマクロならできるとかそんなにはないだろ

>>340
C/C++ のマクロなんて PL/I から見たら子供騙しレベルだけどね
2022/02/28(月) 23:32:29.49ID:7SSxP2tw
>>340
C++に一番近い言語であるRustが多様な各種マクロを充実させているので乗り換えるのもよいかもね
マクロ以外にも非常に多くの問題が解決される
2022/02/28(月) 23:58:07.07ID:EeqSDih1
ゴミのような文化を踏襲してしまった残念言語のRustさんのヘイトを上げるのはやめましょうw
2022/03/01(火) 00:33:34.91ID:Sj28peWv
C++使ってるおれすげーみたいな
2022/03/01(火) 01:06:15.88ID:PkY5rkFL
C++を使いこなせないから皆下流行語の修得を目指す
2022/03/01(火) 06:11:28.76ID:qblu1Z+O
>>343
怪しいって明確に判断できねえのかよ
そもそも俺そんな話してねえし
2022/03/01(火) 06:34:48.00ID:MT73K7Vw
>>343
見てもないコードが明確に判断できたらこえーよ
そんな話じゃないって何いってんのw
2022/03/01(火) 06:35:21.34ID:MT73K7Vw
>>350
アンカー間違った。>>349な。
2022/03/01(火) 07:02:46.96ID:qblu1Z+O
>>350
おまえさん本当にC++使いか?
operator+とoperator+=みたいのの全組み合わせがマクロ使わずにできないとでも思うのか?
2022/03/01(火) 08:36:21.07ID:9lt8ULa+
>>340
Cプリプロセッサを他言語で使ってもいいんですよ。
2022/03/01(火) 09:06:42.29ID:cUOzOJ3p
>>340
マクロを持つ言語は多い
Rustのように用途に応じてマクロが何種類もあるケースもある
2022/03/01(火) 10:19:23.90ID:Hv9eImco
struct B{...}*bP;
struct D1 : public B{...} d1;
struct D2 : public B{...} d2;
bP = (...)? &d1 : &d2;
これって駄目なんですね
2022/03/01(火) 10:40:29.97ID:MQDieCXt
>>355
3項演算子の引数型が互換性のないD1*,D2*だからね

C#9あたりがターゲット型から3項演算子の型推測やってた気がするがC++に導入される日か来るんだろうか
2022/03/01(火) 11:01:53.10ID:Hv9eImco
なるほど
素直にif文にしておきます
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

ニューススポーツなんでも実況