Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(指定なし : 指定なし)
Set a = Nothing について
投稿日時: 21/06/19 23:42:07
投稿者: A太郎

問題集の一つですが下記コードではC行でエラーになるようです。
解説には、変数wsはすでに破棄しているので、C行で変数wsのNameプロパティを取得しようとするとエラーが発生します。とあります。
nothingが裏でのどのような挙動をしているのか知りたいです。
 
ws.nameの値が何であろうが、22を代入できるのではないかと思っていました。
 
*********************************
Option Explicit
Private ws As Worksheet
 
Sub Lesson1()
    Set ws = ActiveSheet
    ws.Name = "11" 'A
    Call Lesson2 'B
    ws.Name = "22" 'C
    Call Lesson2 'D
End Sub
 
Sub Lesson2()
    Debug.Print ws.Name
    Set ws = Nothing
End Sub

回答
投稿日時: 21/06/20 00:49:25
投稿者: simple

Set ws = Nothing
は、少なくともユーザーがそのwsオブジェクトを使わなくなったという意思表示を
したことになります。
したがって、そのあとで、wsは使えません。
 
Lesson2 のなかで、
Set ws = Nothing として、
wsとはオサラバしたわけですから、
そのあとで、
ws.Name = "22"
とされても、Excel君としては、エラーにしますよ、そりゃ。
もう要らないんでしょ?おさらばしたんでしょ?
wsって何ですか?
と言っているわけです。

回答
投稿日時: 21/06/20 12:08:32
投稿者: hatena
投稿者のウェブサイトに移動

simpleさんの回答と被りますが、
Set ws = Nothing
とは変数wsの参照を破棄する言う意味です。
この後は、wsは何も参照しないので、
Nameプロパティ自体ないのでエラーになります。
 
オブジェクト変数はどこからも参照されなくなるか、スコープを抜けると自動で解放されますので、
通常は Set ws = Nothing は必要ないです。
 
ただ、今回のように標準モジュールのモジュールレベルで宣言されるとスコープを抜けることがないので
Set ws = Nothing しないと解放されないことになります。
このような状態はwsの状態が読みづらくなりバグの元になりやすいです。
 
変数のスコープはなるべく狭く、存続期間はなるべく短くなるよう宣言するというのがコーディングのセオリーになります。
 
このような場合は、引数で対象オブジェクトを渡すという手法を覚えておくといいと思います。
 

Sub Lesson1()
    Dim ws As Worksheet 'ここでプロシージャレベルで宣言しておく
    Set ws = ActiveSheet
    ws.Name = "11"
    Call Lesson2(ws)
    ws.Name = "22"
    Call Lesson2(ws)
    
    'Set ws = Nothing ←これはなくても自動で解放される。
End Sub
 
Sub Lesson2(ws As Worksheet)
    Debug.Print ws.Name
End Sub

回答
投稿日時: 21/06/21 08:11:37
投稿者: simple

既に明解な説明がされているので、改めて説明する必要も全くないと思いますが、
なぜか返事がないので、追記してみます。
 
>nothingが裏でのどのような挙動をしているのか知りたいです。
について。
 
Nothingのヘルプには、下記の記載があります。

引用:
キーワード Nothing は、オブジェクト変数とその変数が参照しているオブジェクトとの関連付けを解除するために使います。
これ以上でもこれ以下でもありません。
 
VBAというプログラムの中身を知りたいということですか?
・オブジェクトがどのような内部構造で作成されているかとか、
・オブジェクト変数がどのような構造なのかとか、
・どういうタイミングでメモリーが解放されるか、
・Excel内のオブジェクトではなく、COMオブジェクトの場合はどうか、
とか、そういうことですか?
そうしたことを知る必要はなく、
ヘルプの内容をそのまま理解することで十分な筈です。
仮に説明されてもたぶん理解できないですよ、我々一般ユーザーは。
そしてその知識はVBAのコード作成に直接役立つものでもありません。
 
オブジェクト変数のイメージは、そのオブジェクトへの参照
(その場所へのポインター)というものです。
それを破棄するということです。
端的に言えば、そのオブジェクトとの縁を切るということですよ。
いったん縁を切ったら、
ws.Nameなどとして、参照しようとしてもそれはできません。
-----------------------
なお、
オブジェクト変数の破棄
https://www.moug.net/faq/viewtopic.php?t=80641
について、コメントがあるにもかかわらず放置されています。
それも合わせて、きちんと返事をしてもらいたいですね。

回答
投稿日時: 21/06/22 10:14:30
投稿者: WinArrow
投稿者のウェブサイトに移動

質問に対する回答は、既に回答がありますので、
 
別の観点から、書いてみます。
 
「変数」は「値」を入れる「入物」です。
その「入物」に入れる内容に対応して、
「定義」とか「入れ方」および、「クリア」する方法を選択する必要があります。
「定義」とは、データ型のことですが、同時にスコープを定義します。
配列変数を静的に定義する場合は、配列の大きさ、データ型などを定義します。
「入れ方」とは、
オブジェクト変数の場合は、Set 命令
配列変数を動的に定義する場合は、入れる前に、配列の大きさ、データ型などを定義します。
オブジェクト変数以外は、左辺=右辺の形式で記述します。(左辺は変数名です)
「クリア」とは、入物を空にすることです。
オブジェクト変数の場合は、Set 変数 = Nothing
配列変数は、Erase
オブジェクト変数は、使う場所(スコープ)二よって自動でクリア(解放)されます。
オブジェクト変数、配列変数は、メモリの解放を意味します。
 
どこで何を定義するかは、処理の内容に対応して、自分で考えます。
※例えていうならば、服を着たままお風呂に入るようなことにならないようにということです。
 
 
 

回答
投稿日時: 21/06/22 17:05:54
投稿者: mattuwan44

引用:
nothingが裏でのどのような挙動をしているのか知りたいです。
  
ws.nameの値が何であろうが、22を代入できるのではないかと思っていました。

 
裏とか表とか以前に、
 
変数wsは、「なにもない」と自分で宣言しといて、
何もないものの名前を変えられるわけがないですよね?

投稿日時: 21/06/26 10:40:49
投稿者: A太郎

皆様
解説ありがとうございます。
また返信が遅れたこと申し訳ありません。
nothingは変数の破棄ということで、それ以降使わないことの宣言ということで理解できました。