[c++]dll warning annoying

アバター
purin52002
記事: 235
登録日時: 8年前
連絡を取る:

[c++]dll warning annoying

投稿記事 by purin52002 » 7年前

研究兼趣味で書いているプログラムでdllファイルを作って読み込む必要がでてきました。
嘘です。必要はないです。
ただ「モジュール化したいな。dllっての使ってみるか。」と思いついただけです。

調べてみたらlibファイル作るのとそう変わらないようだったので楽勝^^
と、思っていた時期が僕にもありました^p^

dllでクラスをexportする際、メンバにvectorを持っていると警告が出ます。
(vectorだけではなくmapとかlistでも出るっぽいです)

なんか無視しても問題ない警告らしいのですがうざったいので解消したいです。
色々調べた結果、exportするクラスはインターフェイスクラスが良さげな感じです。

つまりdllでクラスをexportしたい場合は
  • インターフェイスクラス(exportする)
  • インターフェイスクラスを継承したインナークラス(exportしない)
  • インターフェイスクラスを返す関数(exportする)
を作るといいっぽいです。

今回はデータを収集するクラスをdll化しました。

以下コード

エイリアス宣言
► スポイラーを表示
インターフェイスクラス
► スポイラーを表示
インナークラス宣言
► スポイラーを表示
インナークラス定義:主要関数
► スポイラーを表示
インナークラス定義:リーダー関数
► スポイラーを表示
インナークラス定義:設定関数
► スポイラーを表示
インナークラス定義:シャープ関数
► スポイラーを表示
インナークラス定義:シャッフル関数
► スポイラーを表示
公開用関数宣言
► スポイラーを表示
公開用関数定義
► スポイラーを表示
dllなどライブラリを作る際はオブジェクト指向を意識すると良い
(と何処かのサイトで見た気がします^^;)

今回はインターフェース使ってるし、インナークラスのお陰でカプセル化もできてるし、
これはもしかしてオブジェクト指向的なプログラミングというのができたのでは、、、?

コード載せたお陰で文量がすごいですね^^
ランクアップ間違い無し^p^p^

ツッコミお待ちしております^^

YuO
記事: 947
登録日時: 14年前

Re: [c++]dll warning annoying

投稿記事 by YuO » 7年前

通常のクラスをそのままexportしたものは,そのバージョンのコンパイラ以外で使えることが保証されません。
dumpbinなりDependencyWalkerなりでDLLがどういうものをexportしているかを調べればわかるのですが,クラスをエクスポートするのではなく,個々のメンバ関数をエクスポートします。
このため,DLLになったクラスとは通常の関数と異なりコンパイラに依存します。
オフトピック
マングルされた名前がエクスポートされるが,マングルの方法はコンパイラに依存する。
VC++の異なるバージョン間で同一の方法によるマングルがされることは保証されていない。
で,コンパイラ依存しない方法としてはCOMがあるわけですが,色々縛りがあるため使いにくいことも多く,
結果としてC-likeな関数だけをエクスポートする,というのがよくある方法です。


なお,std::vectorなどのclass templateを含む場合,newやdeleteが実行ファイルとDLLで異なると問題が起きることがあります。
実行時に問題が起きる「ことがある」ので,無視してはいけない警告です。
オフトピック
例えばリリースバージョンのCRTDLLをリンクしたDLLとデバッグバージョンのCRTDLLをリンクした実行ファイルなど。
それぞれが内部のnew用領域を持っているため,異なる領域を起源とするオブジェクトのdeleteで失敗します。

アバター
purin52002
記事: 235
登録日時: 8年前
連絡を取る:

Re: [c++]dll warning annoying

投稿記事 by purin52002 » 7年前

Yuoさん

なるほど、第三者に公開する際は関数にしてエクスポートすることにします^^

しかし、クラスをエクスポートせずに関数だけエクスポートする場合、メンバ変数はどのように保持するのでしょうか?
ぱっと思いついたのはInitialize関数でstaticな内部クラス(エクスポートしない)を作って、他の関数でそのクラスを参照する、、、みたいな?
なんか違う気がする^p^p^
オフトピック
「マングル」で検索かけたらなかなか怖い画像がでてきました^p。
あとvectorの警告はやっぱり無視しないほうがいいんですかね。
C4251(dllでvectorをメンバに持つときの警告)で検索すると「無視してもいいよ」みたいなことが書いてあったのですが、
変なバグが起きるのも嫌ですし、対処したほうが良さげですね^^

アバター
usao
記事: 1889
登録日時: 12年前

Re: [c++]dll warning annoying

投稿記事 by usao » 7年前

> クラスをエクスポートせずに関数だけエクスポートする場合

クラスインスタンスのポインタを void * でやりとり(適当にtypedefでそれっぽい型名に見せる).

メンバ関数→明示的にthisを引数を受け取るような形の公開関数.
(実装は単に,引数を実際のクラス型にキャストしてメソッドコールするだけ)

…という形で書いたことがあります.一般的かどうかは不明.

CODE:

typedef void* HMyClass;

//インスタンス生成と破棄
HMyClass Create();
void Destroy( HMyClass hMyClassInst);

//処理
void Func( HMyClass hMyClassInst, int arg1, double arg2 );
最後に編集したユーザー usao on 2017年12月11日(月) 18:30 [ 編集 1 回目 ]

アバター
V30
記事: 21
登録日時: 10年前

Re: [c++]dll warning annoying

投稿記事 by V30 » 7年前

自分が見やすい様に、VS2017[昨日クリーンインストールした最新版]
へコピペして閲覧しました。

いきなり、matrix ってなんや???でつまづく。
(バリバリ3D系のお話だったらお手上げなので、逃げようかと...)

取りあえず、
matrix.h

CODE:

namespace dlib
{
	template  class matrix {};
}
なるものを作ってエラー回避。

そのまま勢いで、Debug開始!

エラー多数。ワォッ!

InnerSamples.h 内の GetBatch(云々) を、MakeBatch(云々) に変更。応急処置。

コンパイル成功!

やったぁ!!!

でも、まだ警告はあるぞ。
あっ! Samples.h が原因だな。
「 dllexport/dllimport を Samples.cpp に追加できません」
って言われたから、SAMPLES_API 取ったら警告なくなった。

次に、InnerSamplesクラスの定義 InnerSamples.cpp を作って namespace RL 内に全部纏めてみる。

・RL名前空間内で RL:: 発見したので、みんな削除。スッキリ。
・名前空間内で他の名前空間名使用は、個人的に消しちゃえ志向。全て using namespace ほにゃらら追加。
・継承クラスのデストラクタ呼ばれない?。。。InnerSamples クラスに、~InnerSamples() 追加。
・InnerSamples::Destroy() は、必要なくなったかも。そもそも、自滅クラスは万病の元。
・InnerSamples::Shuffle() 内のエイリアス化は、せっかく纏めている Define.h に書かなくてもいいのかなぁ?
・Samples.h 内、SamplesInterface.h インクルードしているのに #ifdef SAMPLES_DLL...二重定義。でも、エラー出ない。
・そもそも、SAMPLES_DLL って何なのか、説明もないので分からない。

使用例があると、嬉しかった。
vector 関連で警告は出ませんでした。VS最新版のせい?
unique_ptr については、説明が理解できませんでした。
文脈から、継承クラスが基底クラスの中に入っているという趣旨に聞こえますが、考え方として逆又は、同列ではないかと。
const 参照返しは、見た事がありません。const ポインター返しが一般的だし、過去に問題起きたような記憶が。。。
COMについては、もう話が出ていますね。後出しになるので、割愛。

dllについて細かい説明のできるレベルではないので、パッと見で気付いた(思った)事はこれくらいです。
私は結構アバウトな人間だから、とんでもない返答していたらごめんなさい。
オフトピック
それにしても、素人が見るにはレベルが高すぎる。

アバター
purin52002
記事: 235
登録日時: 8年前
連絡を取る:

Re: [c++]dll warning annoying

投稿記事 by purin52002 » 7年前

usaoさん

voidポインタの存在を忘れていました^^;
c++になってテンプレートができて「voidポインタとか産廃じゃんww」とか思ってました^p^
全然産廃じゃないですね。
縁の下の力持ちさんですね^^

アバター
purin52002
記事: 235
登録日時: 8年前
連絡を取る:

Re: [c++]dll warning annoying

投稿記事 by purin52002 » 7年前

V30さん

matrixは「dlib」というライブラリの行列クラスです。
c++でdeeplearningがしたかったんです^p^

GetBatch->MakeBatchは気づきませんでした^^;

InnerSamplesは __interface Samples を継承しているのですが、
この__interface型がユーザ指定のコンストラクタ、デストラクタをオーバーライドできないみたいなんです。
(インターフェイスクラスだから?)

だからDestroy関数を書いたのですが内容が

CODE:

bool Destroy()
{
    if(this) 
    { 
        delete this;
        return true;
    }
    return false;
}
となっています。
これは王様に「首を切れ!その後わしに向かってウィンクしろ!」と言われているような状況(!?)なのですが、
果たして首を切った後にウィンクはできるのでしょうか、、、?
まだDestroy関数を動かしていないので結果はわかりません^p^

Shuffle内のエイリアス化は多分正規分布のパラメータのことを指しているのだと思います。
これはShuffle内でのみ使う予定なのでとりあえずここに書いときました。

プリプロセッサの二重定義は、、、特に何も考えていませんでした^p^p^
なんか定義の上書き的な何かが行われるんじゃないですか?(適当)

SAMPLES_DLLはエクスポート側のプリプロセッサでした^^;
エクスポートする際はプロジェクトにSAMPLES_DLLが定義されているのでexport修飾子がついて、
インポートする際はinport修飾子がつきます。

使用例^^
使用例^^;
今回は完全に自分用に組んでいたので具体的に上げるのは少し難しいのですが、
データをひとまとめにしたものを沢山集めたい場合に使えるかもしれません。

例えば国語、数学、理科のテストの点数をデータ化して、それをたくさん集めるとします。

CODE:

struct data { int kokugo, suugaku, rika ;};
std::vector data_list;
大体の場合これで事足りると思うのですが、欲しいデータが
「i回目のテストの点数」ではなく、
「kokugoのテストの点数リスト」
だった場合、上記の構造だとstd::vectorをつくる必要があります。
毎回作るのは効率悪そうだったので、今回のSamplesクラスを作りました。

vectr関連は警告が出ないように設定しなおしたのでおそらく正常です^^

unique_ptrについての説明は正直端折っちゃいました^^;
  • STL(おそらくunique_ptrも含む?)をexportしようとすると警告が出る。
  • unique_ptrが保持しているポインタをreset関数以外で消滅させた場合の挙動が不明
  • カスタムデリータでdestroy関数を呼べばよいのでは?
ということです。

const参照返しは正直ちょっと怖いです^^;
普通に動かす分には問題ないような気もするのですが、非同期処理なんかをするとエラーが起きたり?
constポインタ返しはあまり使ったことがないので勉強してきます^^;

ご指摘ありがとうございました^^

アバター
usao
記事: 1889
登録日時: 12年前

Re: [c++]dll warning annoying

投稿記事 by usao » 7年前

deeplearning で何をするんだろう?

アバター
purin52002
記事: 235
登録日時: 8年前
連絡を取る:

Re: [c++]dll warning annoying

投稿記事 by purin52002 » 7年前

usaoさん

強化学習がマイブームです^^
deeplearningで強化学習、、、ではなくて強化学習でdeeplearningを使うつもりです。

画像をパラメータとした非線形回帰を行いたくてdeeplearningを使っているのですが、
ハイパーパラメータの調節とかめんどくさいです^p^

だんだんdeeplearning嫌いになってきます^p^p^