C# と VB.NET の質問掲示板

ASP.NET、C++/CLI、Java 何でもどうぞ

C# と VB.NET の入門サイト

Re[1]: C++/CLI ハンドル変数について


(過去ログ 53 を表示中)

[トピック内 4 記事 (1 - 4 表示)]  << 0 >>

■29286 / inTopicNo.1)  C++/CLI ハンドル変数について
  
□投稿者/ akt (19回)-(2008/12/07(Sun) 12:31:26)

分類:[C++/CLI] 

いつも、お世話になっております。

VS2005でC++/CLIを勉強中なのですが、ハンドル型(^)について理解が進まなくなったので、
助言を頂けたらと思い、書き込み致しました。
(基礎的な内容かとは思いますがすみません)

テスト的に、Windowsフォームアプリケーションプロジェクトを作成して、
以下のようなソースを追加し実行しました。
Form1_Load()がinitBmp()を実行して戻ってきた後、m_bmp->Width, m_bmp->Heightを表示しようとすると、
以下のダイアログが出ます。
---
'System.NullReferenceException' のハンドルされていない例外が System.Drawing.dll で発生しました。

追加情報: オブジェクト参照がオブジェクト インスタンスに設定されていません。
---

現状、私の中ではハンドル(^)はガーベジコレクタメモリ内で扱われるポインタのようなものと
理解しており、C的な感覚で使っていたのですが、理解が間違っているようであり、
どう修正してよいか困っております。

当然、m_bmpを関数呼び出しで初期化せず、Form1_Load内に羅列してgcnewすれば問題はありません。

まとめますと、やりたいことは、
System::Drawing::BitmapやSystem::Stringなど.netクラスを(^)で宣言したとき、
その中身を初期化や変更することを、関数を呼んでその関数内で行いたいとき、
どのような記述にすれば良いのでしょうか。


----以下ソースコード---
private:
	System::Drawing::Bitmap^ m_bmp;  // クラスメンバ変数としてBMPのハンドルを定義

private: System::Void Form1_Load(System::Object^  sender, System::EventArgs^  e)
{
	int width = 320;
	int height = 240;

	initBmp(m_bmp, width, height);

	MessageBox::Show(System::String::Format(L"{0}, {1}", m_bmp->Width, m_bmp->Height));  // <- ここで例外
}


private: System::Void initBmp(System::Drawing::Bitmap^ bmp, int width, int height)
{
	delete bmp;

	bmp = gcnew Drawing::Bitmap(width, height);

	//bmp.SetPixel(0, 0, Color::FromArgb(0));
}
---



引用返信 編集キー/
■29289 / inTopicNo.2)  Re[1]: C++/CLI ハンドル変数について
□投稿者/ 渋木宏明(ひどり) (979回)-(2008/12/07(Sun) 13:59:34)
渋木宏明(ひどり) さんの Web サイト
> 現状、私の中ではハンドル(^)はガーベジコレクタメモリ内で扱われるポインタのようなものと
> 理解しており、C的な感覚で使っていたのですが、理解が間違っているようであり、
> どう修正してよいか困っております。

ポインタだとしても間違ってますよね?

Hoge* m_hoge;

void Load()
{
InitBmp(m_hoge);
}

void Init(Hoge* hoge)
{
delete hoge;

hoge = new Hoge();
}

って、InitBmp() から戻ってきた後に、m_hoge に期待するような値が設定されていると思います?

引用返信 編集キー/
■29290 / inTopicNo.3)  Re[1]: C++/CLI ハンドル変数について
□投稿者/ Hongliang (320回)-(2008/12/07(Sun) 14:01:01)
ネイティブな C++ でも、その(ハンドルをポインタに置き換えたような)コードでは実行時エラーになると思いますが。

m_bmp と bmp は、呼び出し時に参照がコピーされるので同じインスタンスを参照していますが、別々の変数です。
新しいインスタンスを作って参照するようにすれば、当然 m_bmp と bmp は別々のインスタンスを参照することになります。

ネイティブな C++ でも、ポインタ自体の変更を呼び出し元に伝えたい場合、ポインタのポインタやポインタの参照を渡すでしょう。
C++/CLI においてハンドルのハンドルは使用できないので、ハンドルの参照を渡すことになります。ネイティブの参照と区別してトラッキング参照と呼ばれます(GC が追跡できる参照なので"トラッキング")。使用する記号も、ネイティブの参照 & から % に置き換えられています。

でも普通に関数では Bitmap^ を返して Load の中で代入するか、関数自身が直接 m_bmp を操作するかした方がスマートな気がします。
引用返信 編集キー/
■29778 / inTopicNo.4)  Re[2]: C++/CLI ハンドル変数について
□投稿者/ akt (21回)-(2008/12/14(Sun) 16:06:55)
返信が遅れてしまい申し訳ありませんでした。


■No29289 (渋木宏明(ひどり) さん) に返信
>>現状、私の中ではハンドル(^)はガーベジコレクタメモリ内で扱われるポインタのようなものと
>>理解しており、C的な感覚で使っていたのですが、理解が間違っているようであり、
>>どう修正してよいか困っております。
> 
> ポインタだとしても間違ってますよね?
冷静に考えたら、間違っておりました。
ポインタのポインタを渡すような実装にしなければなりませんでした。
Native C++(というかC)の方も理解が怪しいことがわかりました。


■No29290 (Hongliang さん) に返信
> ネイティブな C++ でも、ポインタ自体の変更を呼び出し元に伝えたい場合、ポインタのポインタやポインタの参照を渡すでしょう。
> C++/CLI においてハンドルのハンドルは使用できないので、ハンドルの参照を渡すことになります。ネイティブの参照と区別してトラッキング参照と呼ばれます(GC が追跡できる参照なので"トラッキング")。使用する記号も、ネイティブの参照 & から % に置き換えられています。
> 
> でも普通に関数では Bitmap^ を返して Load の中で代入するか、関数自身が直接 m_bmp を操作するかした方がスマートな気がします。
ありがとうございます。仰るとおりです。



自分でも何がしたかったのか良くわからなくなったのですが、当初は以下のようなことを考えておりました。
ある画像ファイルを開く関数を作成したかったのですが、データ格納用の自作画像クラスから表示用のSystem::Drawing::Bitmapクラスへ
コピーする必要がありました。

--- 当初 ---
private:
	System::Drawing::Bitmap^ m_bmp;		// System::Bitmap
	MyBitmap* m_mybmp;	// 自作クラス
	
	bool OpenFile(System::String^ filepath, System::Drawing::Bitmap%^ bmp, MyBitmap** mybmp)
	{
		delete bmp;
		*bmp = gcnew System::Drawing::Bitmap(filepath);
		
		delete mybmp;
		*mybmp = new MyBitmap;
		
		copyMyBMPToBMP(*bmp, *mybmp)
	}
のようなことを考えており、
	OpenFile(filepath, &m_bmp, &m_mybmp);
のように実行できれば良いなと考えておりました。
OpenFileの実装、特に引数の型は確認しておりませんし、コンパイルは通らないと思います。
こんなようなことをしたかったという感じです。

%^ (^%?)← このような記述の理解ができてないことを自覚しております。

------------

--- 現実装 ---
結局、引数をファイルパスだけにして、メンバ変数に直接入れることにしました。
ポインタのポインタのようなことをして、複雑にするよりクラスメンバ変数なので、
以下のような実装で良いかなと思ったもので。

private:
	System::Drawing::Bitmap^ m_bmp;		// System::Bitmap
	MyBitmap* m_mybmp;	// 自作クラス
	
	bool OpenFile(System::String^ filepath)
	{
		delete mybmp;
		m_mybmp = new MyBitmap;
		
		delete bmp;
		m_bmp = gcnew System::Drawing::Bitmap(filepath);
		
		copyMyBMPToBMP(m_mybmp, m_bmp);
	}
-------------

解決済み
引用返信 編集キー/


トピック内ページ移動 / << 0 >>

このトピックに書きこむ

過去ログには書き込み不可

管理者用

- Child Tree -