C++相談室 part151

■ このスレッドは過去ログ倉庫に格納されています
2020/05/14(木) 11:53:25.59ID:ZPCfyTux
C++に関する質問やら話題やらはこちらへどうぞ。
ただし質問の前にはFAQに一通り目を通してください。
IDE (VC++など)などの使い方の質問はその開発環境のスレにお願いします。

前スレ
C++相談室 part150
https://mevius.5ch.net/test/read.cgi/tech/1584975873/
このスレもよろしくね。
【初心者歓迎】C/C++室 Ver.105【環境依存OK】
http://mevius.5ch.net/test/read.cgi/tech/1556142878/

■長いソースを貼るときはここへ。■
 http://codepad.org/
 https://ideone.com/

[C++ FAQ]
https://isocpp.org/wiki/faq/
http://www.bohyoh.com/CandCPP/FAQ/ (日本語)

テンプレここまで
556548
垢版 |
2020/06/24(水) 16:28:24.79ID:iulgQyvw
皆さんどうもです。状況は (以下、ライブラリ -> lib アプリ -> app)

lib v1.0 リリース
app v1.0 が lib v1.0 をリンクしてビルド、リリース
lib v1.1 リリース(メンバ追加) <- 今ココ
app v1.0 クラッシュ

というわけで lib v1.1 を出すとき小細工して(でもメンバ変数相当を追加したい)
app v1.0 のクラッシュを防げないか、ということです。
とりあえず lib v1.0 には impl メンバはないです。
2020/06/24(水) 16:41:30.01ID:nJwAdMhi
>>555
pimplでバイナリ互換は保証できないよ
2020/06/24(水) 16:48:55.87ID:nJwAdMhi
>>556
インスタンスをnewしてるのがアプリ側だったら
メンバ追加はほぼ絶望的
無理にやるとしたらメンバのアライメントの隙間に数バイトつっこむぐらい

バイナリ互換とる場合はIFはCにするのが定石だよ
(C++でやるなら上にあるとおりcomとかになって複雑になる)
よくわかってないみたいだから頭下げてアプリにビルドしなおしてもらいな
2020/06/24(水) 17:26:36.53ID:L0Gy/Feu
よく分からん
libは兎も角、appはソースあるのが普通じゃね
リンクしなおしている時点で、コンパイルからし直すのも出来るはず

ヘッダのバージョン合ってなきゃそりゃ転けるわ
2020/06/24(水) 18:00:35.46ID:irp07WaX
>>558
newの変わりに、仮想関数のCreateObject()というメソッドを呼ぶ方式があるね。
2020/06/24(水) 18:18:52.62ID:irp07WaX
1. Pimplの場合:
class CXxx {
public:
 (メソッド群)
protected:
 CImpl *pImpl;
};

2. 別解
使う側 :
class CBase {
public:
 virtual CBase *CreateObject();
 (メソッド群)
};
実装する側 :
class CDerived : public Base {
public:
 CBase *CreateObject(); // 実際にはCDeriveの先頭アドレスをCBase*にcastしたものを返す。
 (データメンバ群)
};
2020/06/24(水) 18:26:04.51ID:OmEqu4Is
>>561
その別解とやら、 CBase のインスタンスを得るためにはまず CreateObject() を呼び出すための
CBase のインスタンスが必要になってて、無理じゃね?
2020/06/24(水) 18:35:10.44ID:fimjTN9U
>>547
プロジェクトの範囲内ではテンプレートパラメータが数種類に限られることも多いからそういう時には明示的インスタンス化が利用できるよ
2020/06/24(水) 18:38:06.77ID:q+GJbQMN
>>549
ライブラリ
って知らない?

>>548
バイナリをいろいろなアプリで今後使う予定ならなるべく実装を隠そう
内部で実体の構造体なりクラスなりをnewで作って
外部に公開するクラスは
単にその内部クラスとのインターフェースだけ行う
後から機能を追加出来るように
function(command, param1, param2)
みたいな関数も用意しておく
2020/06/24(水) 18:57:23.17ID:irp07WaX
>>562
言われてみれば。正しい別解の1つは、
class CXxx {
public:
 static CXxx *CreateObject();
 (メソッド群)
};
だね。
2020/06/24(水) 18:59:39.89ID:wsyC1+3+
>>562
なにいってんだ
返すのはポインタだから実体必要ないだろ
2020/06/24(水) 19:01:25.53ID:QJ36Pf9n
>>566
仮想関数呼ぶのには当然同じクラスの実体が必要

cloneなら仮想関数で実装できる
2020/06/24(水) 19:08:20.34ID:irp07WaX
>>565
すまん、こうでなくてはならなかった:
使う側:
class CBase {
public:
 static CBase *CreateObject();
 (メソッド群)
};
実装側:
class CDerived : public Base {
public:
 (データメンバ群)
};
CBase *CBase::CreateObject() {
 return new CDerived;
}
2020/06/24(水) 19:08:44.81ID:wsyC1+3+
>>567
実体のあるクラスをアップキャストすれば必要ねぇだろバカか
2020/06/24(水) 19:17:24.53ID:QJ36Pf9n
何が目的なんだか
その派生クラスのインスタンスを作りたいから、CreateObject呼ぶんだろ?
呼ぶ前に派生クラスのインスタンスが必要って、鶏と卵じゃないか
2020/06/24(水) 19:19:01.22ID:ML+2IMf2
こっそりlib差し替えとか後が怖いなーと思いましたw
2020/06/24(水) 19:24:18.50ID:q+GJbQMN
>>556
今あるメンバ変数の1個をポインタに置き換える
ここに色々なデータが入った構造体のポインタを置く
これで互換性を保てる
2020/06/24(水) 19:27:44.47ID:QJ36Pf9n
ヘッダにオブジェクトの中身を読み書きするinline関数有ったら危険
inlineじゃなくてもtemplateだとヤバイ

まあtemplateで実体生成されないように実装分離してたらセーフかな
2020/06/24(水) 19:29:28.85ID:q+GJbQMN
当然外から直接アクセスする変数は変えたらダメ
2020/06/24(水) 19:42:58.81ID:q+GJbQMN
ヘッダは基本変えない
不便ならポインタに置き換える変数1個だけ型と名前を変える

あとはライブラリ側のコードのみ変更

アクセス関数を後から増やすなら
クラスのポインタとパラメータをパラメータにしたグローバル関数にする

多少使いづらいが
互換性を考えて設計しなかったツケ
2020/06/24(水) 19:48:51.80ID:e6Wuxio/
>>571
巷のOSとか、定期アップデートがかかるときにこういうので悩んだりしないんですかね?

>>572
おお確かにそれでいいんですかね?

まあ今後新たにライブラリを公開することがあるなら最初から気をつけようってことでw
2020/06/24(水) 21:43:18.10ID:N310/pVU
拡張した方は別の型(派生クラス)じゃあかんのか。
2020/06/25(木) 09:10:26.77ID:TVNlb9r7
>>564
知ってます
当たり前でしょそんなこと!
2020/06/25(木) 10:19:29.66ID:X3nsKEKb
>>572
それは、Pimpl方式だけど、それより、>>568の方が書きやすいし、効率も良い。
2020/06/25(木) 10:26:19.02ID:lze6mCYp
>>579
一から書き直せる条件じゃないんのおわかり?
だいたい >>572 をpimplとは呼ばないでしょ
置き換えないメンバはそのまま見えてるわけだから

あとpimpl論議は飽きた
2020/06/25(木) 12:53:57.93ID:yb+enRFi
>>579
互換性を保つのが前提だから
ヘッダは基本今のまま変更不可

っていう前提条件を理解してから書いてね
2020/06/25(木) 18:36:00.50ID:KZb+gCmD
>>580
書き直せないんじゃ、危険だけど>>572くらいしかないんじゃない?

そんな暗黒魔法使うくらいならapp1.0を再コンパイルする方法を考えるけどね。
2020/06/25(木) 18:41:27.48ID:/eSpQqPW
ヘッダは変更するの前提じゃないの?
バイナリ互換させるの前提なのだから
2020/06/25(木) 19:04:50.22ID:X3nsKEKb
「メンバ変数の一個をポインタに置き換える」
こともヘッダを変更するのが必須になると思うのだが。
2020/06/25(木) 19:07:11.43ID:TznTPNyN
>>584
必須じゃない
2020/06/25(木) 19:13:33.80ID:g2od3l7G
実装側でアクロバットするのは無理やりバイナリ互換させる旧バージョン対応の方で良い

新バージョンの中身にあわせてヘッダを更新しておかないと、負の遺産が延々と続くことになる
2020/06/25(木) 19:14:44.69ID:L+/QiPNH
>>584
やり方次第。
privateのint変数やポインタ変数があるなら、キャストしてぶちこめばいい。
他の変数も似たようなもん。
2020/06/25(木) 19:16:18.79ID:X3nsKEKb
>>587
ええ!!??
2020/06/25(木) 19:27:44.15ID:aCPUEpAO
バイナリ互換をはじめてかんがえた
って感じの人が多くて驚く
2020/06/25(木) 19:27:52.99ID:g2od3l7G
pointerに置き換えたとして、指す先の実体の管理はどうするんだ
元々デストラクタが外部定義されてないと、デフォルトのデストラクタ呼び出しはinline化されてしまっている
2020/06/25(木) 19:32:44.29ID:aCPUEpAO
なんでインラインだと思ったんだか
2020/06/25(木) 19:34:45.97ID:aCPUEpAO
ライブラリ作ったこと無いのかな?
2020/06/25(木) 19:36:15.68ID:g2od3l7G
いや、はじめからバイナリ互換させる前提で設計したライブラリでもない限り、小手先の対応でなんとかなる場面は物凄い限られるよ
2020/06/25(木) 19:38:38.17ID:aCPUEpAO
>>593
それは互換性を保つ技術が無いから
2020/06/25(木) 19:41:06.01ID:aCPUEpAO
メモリアラインメント調整等で発生する隙間を集めて変数として使う
っていう手もある

データ構造互換だとよくやる手法
2020/06/25(木) 19:41:55.04ID:L+/QiPNH
>>590
そんなもん、GC実装して無理やりゴミ集めするしか無いだろ。
最後はアプリ終了時にOSが処分してくれることを期待するしかない。
2020/06/25(木) 19:42:42.30ID:g2od3l7G
バイナリ互換前提で開発されていないから、問題が出ているんじゃないの?

appがコンパイルされた時点で、デストラクタやらコピコンやら代入やらをすべて明示的に外部定義していないと、コード中で必要に応じてデフォルトが呼ばれて、当然inline化もされてしまう
2020/06/25(木) 19:43:40.85ID:jUSiql3P
>>591
必ずインライン化されてるとは言えないけど、可能性はあるよね?

結局のところ具体的なコード要件を >>548 が言わない限りは不毛な気もする。
2020/06/25(木) 19:44:07.37ID:aCPUEpAO
>>597
>>592
2020/06/25(木) 19:45:52.88ID:aCPUEpAO
ライブラリを作った事がないヤツが
ライブラリの互換性についてアドバイスしようとしてて笑える
2020/06/25(木) 19:47:42.56ID:g2od3l7G

ライブラリ作ったことあるからこその内容だろうに
GCするとか、リークしたままOSに回収させるとかそれこそライブラリとしてあり得ない対応だろう
2020/06/25(木) 19:51:39.44ID:aCPUEpAO
なんでデストラクタがインラインだと思うんだ?
2020/06/25(木) 19:55:22.62ID:g2od3l7G
デフォルトだとinlineのデストラクタが生成されるのがc++の仕様だろ
じゃないと単なるプレーンな構造体でもデストラクタの呼び出しするはめになる
2020/06/25(木) 20:01:17.97ID:aCPUEpAO
クラスをライブラリ化するのにメンバ関数がインライン?

ご冗談を
2020/06/25(木) 20:02:21.68ID:aCPUEpAO
デストラクタがインラインなら>>595
2020/06/25(木) 20:05:18.94ID:g2od3l7G
バイナリ互換想定してないなら、inlineしない方が稀じゃね
全部外部定義だと、高速化の妨げになるじゃないか
世の中のc++用ライブラリを見てみれば良いさ
inlineが無いどころかheader onlyが幅を利かせている
2020/06/25(木) 20:08:52.95ID:g2od3l7G
alignmentサイズの隙間に入れたところで、コピーの時にコピーされるかどうかも不明
と言うか、単体だとまずされない
まあコピーも外部定義されていれば置き換え可能だけど
2020/06/25(木) 20:10:03.10ID:L+/QiPNH
>>599
そもそもバイナリ互換を考慮していないライブラリを今さら何とかしようとするウンコな発想ありきだからな。

まともなライブラリ実装者なら
「そんなクソとっとと便所に流してマトモなもの作り直せ」
としか言わんわ。
2020/06/25(木) 20:11:42.55ID:Y+MR3z5H
>>606
テンプレートだろそれ
2020/06/25(木) 20:13:29.88ID:Y+MR3z5H
>>607
コピーもインライン前提か?
2020/06/25(木) 20:14:36.46ID:g2od3l7G
inlineじゃないtemplateのヘッダオンリーでも、バイナリ互換保つの無理だよね
例えinline化されてなくても、各obj内で実体化されたtemplate関数が同一じゃないと何が起こっても文句言えない
2020/06/25(木) 20:15:41.12ID:g2od3l7G
明示的なinlineもだけど、定義せずコンパイラに任せた場合デフォルトで出来るものはinline扱いになる
2020/06/25(木) 20:16:21.51ID:Y+MR3z5H
なんでobj?
ライブラリっていってるんだからlibだろ
2020/06/25(木) 20:18:38.89ID:g2od3l7G
libはobjの集合だろうに
2020/06/25(木) 20:19:42.46ID:Y+MR3z5H
インライン混じりのライブラリ
ならメンバ変数を増やすのを心配する以前だろ

問題が変わってる
2020/06/25(木) 20:27:59.07ID:Y+MR3z5H
>>611
だからヘッダは基本変更しない
2020/06/25(木) 20:29:04.78ID:iE0yhaVV
どうしても必要なことなら、
ライブラリの中にスタティックな連想配列置いて、thisアドレスをキーにして追加したいメンバ変数引くようにしたら?
トリッキーでないし確実に動く
2020/06/25(木) 20:29:54.44ID:g2od3l7G
コピーされなきゃ良いよね
2020/06/25(木) 20:30:23.57ID:g2od3l7G
vectorで持たれてても再配置されたら困るし
2020/06/25(木) 20:32:18.93ID:Y+MR3z5H
>>617
インラインかもよ
コンストラクタもデストラクタもコピーも
追加したメンバ変数へのアクセスも
2020/06/25(木) 20:34:29.24ID:Y+MR3z5H
何の互換性を保ちたいのかわからなくなってきた
2020/06/25(木) 20:42:06.05ID:N8mY4JDD
同感
2020/06/25(木) 21:13:19.28ID:Y+MR3z5H
ライブラリを使う(一部の)コードはコンパイル済みでリコンパイル出来ない

コンパイル済みのコード内で使ってるクラスのメンバ変数を追加したい

当然
クラスのサイズは変えられないし
コンパイル済みのコード内の(インライン展開されてる)関数も変えられない

どの関数がコンパイル済みコード内にあって
どの関数がライブラリ内にあるかは不明
2020/06/25(木) 21:14:06.17ID:Y+MR3z5H
こんな感じ?
2020/06/25(木) 21:25:58.94ID:GV91Na/E
ほとんど読んでないけどID:aCPUEpAOとID:Y+MR3z5Hがド素人なのはわかった
2020/06/25(木) 21:27:27.39ID:Y+MR3z5H
はいはいwww
2020/06/25(木) 21:32:36.99ID:GV91Na/E
ヘッダの変更無しにどうやって新しい機能追加すんだよ
2020/06/25(木) 21:39:56.91ID:Y+MR3z5H
機能を追加したいなんて言ってたか?
2020/06/25(木) 21:40:05.85ID:GV91Na/E
と思ったら>>548が前提なのか、すまん
とりあえずインスタンスそのままで扱うのは無理じゃね
ユーザー側が一貫してポインタで扱うのは必須だと思う
2020/06/25(木) 21:46:21.80ID:Y+MR3z5H
なにそのド素人発言
2020/06/25(木) 21:47:56.11ID:GV91Na/E
>>610,613,615
2020/06/25(木) 21:49:41.84ID:GV91Na/E
インスタンスで扱ってるなら暗黙定義された関数の動作が変わる可能性くらいすぐ気づけやド素人が
2020/06/25(木) 21:58:47.71ID:W+LR7rOf
ポインタで扱うとインライン関数がリコンパイル無しで変えられるって?
2020/06/25(木) 22:01:17.65ID:W+LR7rOf
ライブラリなんだから
メンバ関数は全てライブラリ側で実装するだろ普通

テンプレートとか別途リンクが不要なことが売りなライブラリならともかく

何のためのライブラリだか
635632
垢版 |
2020/06/25(木) 22:05:49.15ID:Q7o8gz5q
>>633
ヒント:仮想関数、コピー不可、Factory
2020/06/25(木) 22:06:38.78ID:Q7o8gz5q
てかこの要件だと>>617ですでに答え出てる気がする
2020/06/25(木) 22:06:48.48ID:W+LR7rOf
案を出せない人間が何を言っても負け犬の遠吠え
2020/06/25(木) 22:09:27.67ID:W+LR7rOf
>>636
>>572に対してメリットあるか?
2020/06/25(木) 22:11:36.08ID:W+LR7rOf
>>635
あれ?
もしかして
互換性保持した修正はギブアップで
依頼者の要件を無視した案を言ってる?
2020/06/25(木) 22:14:20.52ID:Q7o8gz5q
>>637
っ[鏡]
てかID変えたんか?

>>638
>>573
2020/06/25(木) 22:15:15.45ID:Q7o8gz5q
>>639
>>633に対して反論したんだが
すり替えてんじゃねーよ
2020/06/25(木) 22:16:59.09ID:W+LR7rOf
外部から直接アクセスしない変数を置き換えるに決まってるたろ

連想配列だと
初期化順とかスレッド安全とかパフォーマンスとか
色々と心配だねえ
2020/06/25(木) 22:20:39.99ID:lze6mCYp
>>636
どこが答えだよ
>>617 は無理だよ
アプリ側でnew/deleteされたことをライブラリ側はトラッキングできない
アプリ側でnew/deleteされてないのだったら問題になってない
アプリに手を加えていいのだったらバイナリ互換考えなくていい
2020/06/25(木) 22:20:56.12ID:W+LR7rOf
>>641
>>632はお前だろ?
2020/06/25(木) 22:26:37.67ID:Q7o8gz5q
>>643
新しいthis来たら新しく作るだけだろ
deleteに対してはどうにもできんけど

>>644
馬鹿かお前は
ポインタで扱う前提に乗っかったのはお前だろ
バカにしようとして自爆したのに逆ギレか
2020/06/25(木) 22:26:45.54ID:W+LR7rOf
コピーを使わない、もしくはインラインじゃないなら>>595

コンストラクタ、デストラクタ、コピーがインラインじゃないなら
>>572で良い

new deleteはアプリ側でもライブラリ側でも問題ない
2020/06/25(木) 22:29:26.54ID:Q7o8gz5q
何言ってんだこいつ
2020/06/25(木) 22:29:51.27ID:W+LR7rOf
コンストラクタはインラインでも>>572で問題ないね
2020/06/25(木) 22:35:32.05ID:W+LR7rOf
>>643より>>572の方が良いね
隙間があってコピーで問題なければ>>595
2020/06/25(木) 22:36:49.66ID:W+LR7rOf
>>643じゃなかった
連想配列案
2020/06/25(木) 22:47:52.28ID:Q7o8gz5q
インラインじゃないならって、普通コンパイルオプションやnoinlineで指定してない限り、
実装が見えているメンバ関数は全てインライン展開はされうるんだぞ

そんな厳しい前提がOKなら>>645で言ったdeleteの問題だって対処できる
2020/06/25(木) 22:50:51.97ID:W+LR7rOf
>>572>>617
デストラクタがインラインだとダメなのは同じ
コピー時の制約も同じ

速度、スレッド安全性、初期化順などの心配事に関しては>>572の勝ち

>>572は外部からアクセスしていないポインタサイズの変数の存在が条件
2020/06/25(木) 22:54:30.29ID:W+LR7rOf
>>651
ヘッダにない関数はインラインにしようがない
2020/06/25(木) 22:59:14.54ID:W+LR7rOf
>>572>>595のスペースが全く無いなら他の方法を考えるしかないけど
2020/06/25(木) 23:01:53.27ID:W+LR7rOf
デストラクタ問題に対応出来るのは今のところ>>595だけ
■ このスレッドは過去ログ倉庫に格納されています
5ちゃんねるの広告が気に入らない場合は、こちらをクリックしてください。

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