Excel VBAでNothing判定を行う方法をお探しですね。
広告
Excel VBAの「Nothing」判定とメモリ解放を分かりやすく解説
Excel VBAでWorkbookやWorksheet、Range、Dictionaryといったオブジェクト変数を使っていると、「この変数にはオブジェクトが入っているのかな?」「使い終わったらNothingを代入した方がいいのかな?」と迷うことがありますよね。
Nothingは単なる空文字や0とは違って、オブジェクト変数が何も参照していない状態を表す特別な値なんです。
この記事では、Excel VBAでオブジェクトの「Nothing」判定を行う方法と、メモリ解放について初心者の方にも分かりやすく整理していきます。
1. Excel VBAの「Nothing」って何?
Excel VBAの「Nothing」とは、オブジェクト変数が何も参照していない状態のことです。
例えば、Worksheet型の変数を宣言しただけで、まだ特定のシートをSetしていない場合、その変数はNothingの状態になっています。
数値型の0や文字列型の空文字とはまったく別物で、WorkbookやWorksheet、Range、Object、Collectionなどのオブジェクト型変数に対して使います。
オブジェクト変数には、オブジェクトそのものが入るわけではなく、対象オブジェクトへの「参照」(つまり、どこにあるかを示す情報)が格納されます。
Nothingは「参照先がない」という意味なので、この考え方を理解しておくと、後で説明するメモリ解放の話も整理しやすくなりますよ。
オブジェクト変数に値を入れるときは、普通の代入とは違って「Set」というキーワードを使います。
例えば、`Set ws = ThisWorkbook.Worksheets(“Sheet1”)`と書くと、変数wsはSheet1を参照するようになります。
反対に、`Set ws = Nothing`と書くと、変数wsからSheet1への参照が解除されます。
ここで大事なのは、Nothingを代入した瞬間に必ずオブジェクトそのものが消えるわけではないという点です。
同じオブジェクトを別の変数やExcel本体が参照していれば、そのオブジェクトは残ります。
Nothingは「変数とオブジェクトのつながりを切る操作」であって、「対象を完全に削除する命令」ではないんですね。
2. If文とIs演算子でNothing判定をする方法
Excel VBAでオブジェクトがNothingかどうかを判定するときは、`=`ではなく`Is`という演算子を使います。
ここは初心者の方がよくつまずくポイントなんですが、`If ws = Nothing Then`のようには書けません。
Nothingは普通の値ではなく、オブジェクト参照の状態を比較するためのものなので、`If ws Is Nothing Then`と書く必要があります。
逆に、オブジェクトがちゃんと設定されていることを確認したいときは、`If Not ws Is Nothing Then`と書きます。
オブジェクト変数を操作する前にNothing判定を入れておくと、「オブジェクト変数またはWithブロック変数が設定されていません」という実行時エラーを防ぎやすくなります。
基本的な書き方は次のような感じです。
ワークシートを取得できた場合だけ処理して、取得できなかった場合はメッセージを出す、といった分岐に使えます。
“`vb
Sub CheckNothing()
Dim ws As Worksheet
On Error Resume Next
Set ws = ThisWorkbook.Worksheets(“Data”)
On Error GoTo 0
If ws Is Nothing Then
MsgBox “Dataシートが見つかりません。
”
Else
ws.Range(“A1”).Value = “処理を開始します”
End If
End Sub
“`
この例では、存在しないシート名を指定した場合でも、エラーで処理を止めずにwsがNothingかどうかを確認しています。
ただし、`On Error Resume Next`を広い範囲で使い続けると別のエラーまで見逃してしまうので、必要な箇所の直後で`On Error GoTo 0`に戻すのが安全です。
Nothing判定は、エラーをごまかすためではなく、「オブジェクトが使える状態かどうか」を明示的に確認するために使うと考えると、保守しやすいコードになりますよ。
3. Set obj = Nothingはメモリ解放になるの?
`Set obj = Nothing`は、オブジェクト変数から参照を解除する処理です。
VBAでは、オブジェクトがどこから参照されているかを自動で管理していて、参照がなくなった時点で破棄される仕組みがあります。
なので、あるオブジェクトを参照している変数が1つだけで、その変数にNothingを代入すれば、結果としてオブジェクトが解放されることがあります。
ただし、別の変数も同じオブジェクトを参照している場合、片方をNothingにしてもオブジェクトは残ります。
つまり、Nothingはメモリ解放のきっかけにはなりますが、常に即座に解放されることを保証するものではないんです。
プロシージャ(SubやFunction)の中で宣言したローカルのオブジェクト変数は、通常、そのプロシージャが終了すると有効期間も終わって、参照は自動的に解除されます。
なので、End Subの直前で使用済みのローカル変数をすべて`Set ~ = Nothing`にすることは、実はそれほど大きな意味を持ちません。
一方で、処理の途中で大きなブックや大量のRange、外部アプリケーションなどを使い終えて、その後もまだ長い処理が続く場合は、使い終わった時点でNothingを代入するとメモリやリソースの無駄を減らせます。
また、「この変数はここから先では使わない」とコード上で示せるので、後から読む人にとっても意図が分かりやすくなりますね。
特に注意したいのは、プロシージャの外で宣言したモジュールレベル変数、Public変数、Static変数です。
これらは普通のローカル変数と違って、プロシージャが終わっても参照が残ることがあります。
参照を保持し続ける必要がないなら、明示的に`Set obj = Nothing`を実行しておく方が安全です。
Excel VBAでメモリ解放を考えるときは、「すべての変数を最後にNothingにする」よりも、「寿命の長い変数や重いオブジェクトを、不要になったタイミングで解放する」という判断の方が実務的ですよ。
4. Workbook・外部オブジェクト・循環参照で注意すべきこと
Workbookや外部アプリケーションを扱う場合、`Set obj = Nothing`だけでは不十分なことがあります。
例えば、VBAで別のExcelブックを開いた場合、変数にNothingを代入してもブック自体が閉じるわけではありません。
ブックを閉じるには、まず`wb.Close SaveChanges:=False`のようにWorkbook自身のCloseメソッドを呼んで、その後で`Set wb = Nothing`として参照を解除します。
外部アプリケーションも同じで、Internet Explorerや他のCOMオブジェクトを作成した場合は、対象が持つQuitやCloseなどの終了メソッドを実行してからNothingを代入するのが基本です。
終了メソッドはアプリケーションやオブジェクトを閉じる操作で、Nothingは VBA側の参照を切る操作なので、役割が違うんですね。
実務で使いやすい後始末の形は、正常終了時もエラー発生時も同じ場所で解放処理を行う書き方です。
次のように、最後に必ずCloseとNothingを通す構成にしておくと、途中でエラーが起きてもブックを開きっぱなしにするリスクを減らせます。
“`vb
Sub OpenBookSafely()
Dim wb As Workbook
On Error GoTo ErrHandler
Set wb = Workbooks.Open(“C:\Temp\Sample.xlsx”)
‘ ここにブックを使った処理を書く
ExitHandler:
If Not wb Is Nothing Then
wb.Close SaveChanges:=False
Set wb = Nothing
End If
Exit Sub
ErrHandler:
MsgBox “エラーが発生しました: ” & Err.Description
Resume ExitHandler
End Sub
“`
もう1つ見落としやすいのが「循環参照」です。
循環参照とは、オブジェクトAがオブジェクトBを参照していて、同時にBもAを参照しているような状態のことです。
VBAの参照管理では、互いに参照し合っていると参照数が0にならず、変数にNothingを代入してもオブジェクトが破棄されない場合があります。
クラスモジュールやCollectionでオブジェクト同士を保持する設計をしている場合は、終了前に片方の参照を明示的に切る、CollectionからRemoveする、親子参照を解除するなどの処理が必要です。
Nothing判定とメモリ解放を正しく使うには、単に`Set obj = Nothing`を書くかどうかではなく、どこに参照が残っているかを意識することが大切です。
最初は難しく感じるかもしれませんが、慣れてくると自然に考えられるようになりますよ。
広告
