[[20090303232447]] 『Set ** = Nothingは ?』(勉学中) ページの最後に飛ぶ

[ 初めての方へ | 一覧(最新更新順) | 全文検索 | 過去ログ ]

 

『Set ** = Nothingは ?』(勉学中)
 [[20090112165616]]を 参考に見ていたのですが
  Sub 計算並べ替え()
    Dim dic As Object, rng As Range, i As Long, j As Long, tbl, x
    Set dic = CreateObject("scripting.dictionary")
    Set rng = Selection
    If rng.Columns.Count > 2 Then MsgBox "範囲が不完全でっせ!": Exit Sub
    tbl = rng.Value
    ReDim x(1 To UBound(tbl, 1), 1 To UBound(tbl, 2))
    For i = 1 To UBound(tbl, 1)
        If Not dic.exists(tbl(i, 1)) And Not IsEmpty(tbl(i, 1)) Then
            j = j + 1
            dic(tbl(i, 1)) = j
            x(j, 1) = tbl(i, 1)
            x(j, 2) = tbl(i, 2)
        Else
            x(dic(tbl(i, 1)), 2) = x(dic(tbl(i, 1)), 2) + tbl(i, 2)
        End If
    Next i
    rng(1, 1).Resize(UBound(tbl, 1), UBound(tbl, 2)).ClearContents
    rng(1, 1).Resize(j, 2) = x
    Set rng = rng(1, 1).Resize(j, 2)
    rng.Sort key1:=rng(1, 1), order1:=xlAscending
 End Sub
 上記に Set dic = Nothing が なぜ必要でないか分かりません
 なにぶん 低レベル質問ですが教えていただけませんか?

 こんにちは。かみちゃん です。

 > 上記に Set dic = Nothing が なぜ必要でないか分かりません

 単純に記述がもれているだけではないでしょうか?
 なくても問題はないのかもしれませんが、あったほうがより確実ですので、できるだけ記述したほうが
 いいのではないでしょうか?

 (かみちゃん)
 2009-03-04 00:14


 かみちゃんさま早速の返答ありがとうございます。

 いろいろ素人ながら考えていたのですが

 > あったほうがより確実ですので、できるだけ記述したほうがいいのではないでしょうか

 の回答で解決しました。(勉学中)
 
 


 まだ見て居られるか分かりませんが、過去ログです。
[[20041124212113]]『VBA:変数の開放の必要性』(みやほりん) 

 (HANA)

 HANAさま、遅くなりましたがありがとうございます。

 過去にいろいろ高度の検証等をしていたのですね 

 貴重な参考を教えていただきありがとうございました。【感】

 学校の皆様共々これからもよろしくお願いします。(勉学中)

 私は、自信を以て書いている人が一人も居ない、と云う感想を持ちました。

 マイクロソフトの記述でさえ、確信に満ちたものではない。

  >プロシージャの内部で宣言した変数はプロシージャの終了時に破棄されますが、・・
 これが確実なら、「End Subの直前でNothingを設定する」のは馬鹿げている、
 と結論付けるのが「リーズナブル」と云うものではないでしょうか。

 ・・にも拘わらず、
  >オブジェクト変数を使う場合には、自動化しているアプリケーションを終了するときに、
  >明示的にオブジェクト変数に Nothing キーワードを設定してオブジェクトを
  >破棄するようにするとよいでしょう。。
 不思議にも(イラつくことに)、Nothing設定を推奨する根拠が何も書かれていない。

 また、それは「自動化しているアプリケーションを終了するとき」だけである。つまり「いつも」ではない。
 これからしても、「普段は、End Subの直前でNothingを設定する」のは、意味がないと思えてしまいます。

 (半平太) 2009/03/08 09:48

 自己レスです。 <(_ _)>

 >不思議にも(イラつくことに)、Nothing設定を推奨する根拠が何も書かれていない。
 英語の原文にその根拠が書かれていないか調べて見たのですが、原文そのものの特定が難しい。(^^ゞ
 もし、これだとすると
     ↓
 Shutting Down an Object Created by Using Automation
http://msdn.microsoft.com/en-us/library/aa164488(office.10).aspx

 明示的にNothingを入れて破棄すれば、アプリケーションレベルのオブジェクト変数が関わったメモリを全て解放させられる様です。
 つまり、暗黙的に破棄する方法では、一部ゴミが残る余地がある(らしい)。

 そうすると、あとは Dictionaryオブジェクトがアプリケーションレベルのオブジェクトかどうかだと思いますが、
 その記事によると、アプリケーションオブジェクトには、Application.Controlプロパティがあるとの事なので、
 ローカルウィンドウでDicをチェックした限りでは、無かったです。ただ、そんなチェックでいいのかどうか不確かです。

 (半平太) 2009/03/08 16:17

 Dicは、「Dictionary」オブジェクトであって、「Application」オブジェクトではないのは明らかでした。トホホ (^^ゞ

 (半平太) 2009/03/08 19:07

 コーディングポリシーとして、Set xx=Nothingは記述しておくべきだ という意見です。

 新規ブックと同じフォルダ上にSample.Txtというファイルを作成し,”aaa”というデータを書き込む
 ファイル作成後、Excelを終了する

 という仕様を考えた時、

 Sub main()
    Dim flno As Long
    Const flnm = "sample.txt"
    Const wdata = "aaa"
    flno = FreeFile
    Open ThisWorkbook.Path & "\" & flnm For Output As flno
    Print #flno, wdata
    Close #flno
    ThisWorkbook.Saved = True
    Application.Quit
 End Sub

 上記のようなコードを記述しましたが、これ実は、この仕様の場合、

 Close #flno

 を記述しなくても結果的には、作動します。

 OSのターミネータがタスク終了時にオープンされているファイルを閉じるという処理をしてくれるからです。
 でも、だからって、上記のコードでは、Closeは要らないから記述しなくて良い
 と言えるか否か? です。

 私も時折、この問題を目にした場合、よくこの例を引用します。

 さて、オジェクトのNothingの件に戻ると、
 モジュールレベルで何らかの オブジェクト変数を宣言した場合は、
 このスレッドでも引用されているスレッドでも

 Set xx=Nothingは記述しておくべきだ

 という意見でほぼ統一されていますよね!!
 私もこれに異論はありません。
 クラスモジュールを扱えばわかりますが、
 Class_Terminate() というイベントプロシジャーが存在するのですから、
 対象のオブジェクトがここで、重要な後処理を行っているかもしれないからです。

http://www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=28597;id=excel

 ここでSet xx=Nothingをしないときの例を投稿したことがありました。

 では、プロシジャーレベルで宣言したオブジェクト変数は?

 Nothingにより、ほかの変数がそのオブジェクトを参照していなければ、それまでに参照していたオブジェクト に割り当てられているすべてのシステム リソースおよびメモリ リソースが、解放されます。

 とHelpにはあります。

 基本的には、プロシジャーレベルで宣言されたオブジェクト変数は、
	Set xx=Nothing
 の記述がなくてもプロシジャー終了時に変数が開放されるので必要がない とされています。
 (これ、ゴミが残ってそれで初期化されないなら、これはバグだよね!!)

 ならば、

 プロシジャーレベルで宣言されたオブジェクト変数では、
	Set xx=Nothing
 要らないのか?

 状況は、冒頭のファイルの場合と同じです。

 冒頭のファイルの場合、何故、Closeは入れておくのか?
 将来、何らかの変更・機能拡張が発生した時のメンテナンス性を考慮するからです。

 同じようにプロシジャーレベルで宣言していたオブジェクト変数が
 将来、何らかの変更・機能拡張のためにモジュールレベルの変数に移行する必要性が発生した時、
 メンテナンス性を考慮すると、Set xx=Nothingの記述があった方が間違いが少ないからです。

 他人のプログラム(自分がだいぶ前に作成したコードでもよいです)を読むときに

 プログラムの構造を

 前処理

 一回以上のループ処理

 後処理

 という基本構造を考えた場合、前処理でインスタンスの作成処理

  set xx=createobject(“xxx.yyyy”)
  または、set xx=new xxxx

 が行われていて、

 後処理で

  set xx=nothing

 の記述がないと不安になりませんか? どこで後始末をしているのだろう って・・・。

 メンテナンスがしやすいというコーディングポリシーとして、
 Set xx=Nothingは記述しておくべき

 が私の意見です。

 ichinose


 私の論旨は「Close #flno が不要」と云うものではありません。
 そんなことまで言及しておりませんし、その適否について調べてもおりません。

 単に、オブジェクト変数の参照を断つ(=Nothingを設定する) と云うコーティングを
 End Subの直前に書くことは、屋上屋を架すのと同じ行為ではないか、と云うことに絞った論議です。

 仕様に沿って、無駄なことが止められるなら、止めたいのです。
 何故、こんなシンプルな原則が、理解されないのか不思議です。

 > 基本的には、プロシジャーレベルで宣言されたオブジェクト変数は、
 > Set xx=Nothing
 > の記述がなくてもプロシジャー終了時に変数が開放されるので必要がない とされています。
 これが信頼に足る仕様なら、Set ** = Nothing をEnd Subの直前に入れるのは、無駄と云うしかないです。

 > 冒頭のファイルの場合、何故、Closeは入れておくのか?
 > 将来、何らかの変更・機能拡張が発生した時のメンテナンス性を考慮するからです。
 Nothingを入れるコーディングと、FileをCloseするコーディングが、
 メンテナンス性に於いて同じレベルにあるとも思えません。

 > 同じようにプロシジャーレベルで宣言していたオブジェクト変数が
 > 将来、何らかの変更・機能拡張のためにモジュールレベルの変数に移行する必要性が発生した時、
 > メンテナンス性を考慮すると、Set xx=Nothingの記述があった方が間違いが少ないからです。
 私は、これを理解出来るレベルにありません。必要と思う人は励行していただくのが良いと思うだけです。
 私にとっては、Nothingを設定しないことが直接的な問題を引き起こす訳では無い、と云う意味合いの方が大きいです。

 > メンテナンスがしやすいというコーディングポリシーとして、
 > Set xx=Nothingは記述しておくべき
 今まで、メンテナンス上で必要だと論じた人はいませんでした。
 何らかの(直接的な)トラブルが生ずる(かも知れない)、と云うものしか目にしていません。
 しかし、そのトラブルが何なのかクリアーに示されたことはありません。

 > set xx=nothing の記述がないと不安になりませんか?
 > どこで後始末をしているのだろう って・・・。
 以前は不安でした。
 今は、最後に書くたびに馬鹿げたことをしているのではないか思う不安の方が大きいです。
 必要だと論じる人は、何故、参照が不要になった直後に書かないのだろうか?
 それなら少しは意味もあるのだが、不思議でしょうがない。

 (半平太) 2009/03/09 13:09

 >私の論旨は「Close #flno が不要」と云うものではありません。
 >そんなことまで言及しておりませんし、その適否について調べてもおりません。
 同じように省略しても動作する例を上げたまでです。
 調べてなくてもこれが事実だと仮定して考えてみてください。

 例にあげたコードでは、Closeの省略、
 プロシジャーレベルで宣言されたオブジェクト変数に対する
      Set xx=Nothingの省略 
 省略しても動作するなら要らない?、よく似ていると思います。

 >End Subの直前に書くことは、屋上屋を架すのと同じ行為ではないか、と云うことに絞った論議です。
 本来、コーディングで記述すべきステートメントを省略している事に対する是非を申し上げています。
 私には、一緒に見えますけどねえ。

 例にあげたコードは、どうせOSがやってくれるから、Closeは省略してもいいや と、
 オブジェクト変数は、End Sub の時点でインタープリタがNothingしてくれるから、Set・・・・は、省略してもいいや・・・  

 OSがアプリ終了時に掴んでいた資源を解放(ファイルのクローズを含む)するのは、
 本来は、アプリがすべき処理をしていないのでやってくれるんですよね?
 End Subでオブジェクトを開放するのも本来は、コーダーが宣言した変数なんだから、
 コーダーが開放すべきものなのに仕方なくインタープリタがやってくれるんだと解釈し、
 コードには、 Set ・・・Nothingを記述することが
 私が申し上げているコーディングポリシーです。

 >これが信頼に足る仕様なら、Set ** = Nothing をEnd Subの直前に入れるのは、無駄と云うしかないです
 無駄とは、Set・・・を記述する手間ですよね?
 でも、書くほうは、良いですが、省略されたコードを読むほうはこの1行があれば、
 きちんと後処理が施されている分かりやすさがあると思います。
 処理速度もほとんど変わらないと思いますよ。

 >Nothingを入れるコーディングと、FileをCloseするコーディングが、
 >メンテナンス性に於いて同じレベルにあるとも思えません。
 わかりやすいは、メンテナンスしやすい と解釈していますが・・・。
 例
 新規ブックにて

 クラスモジュール(class1)にて、

 Option Explicit
 Private bk As Workbook
 Private Sub Class_Initialize()
    Set bk = Workbooks.Add
 End Sub

 Private Sub Class_Terminate()
    bk.ActiveSheet.Range("a1:d10").Value = "owari"
    MsgBox "終わり"
    bk.Close False
    Set bk = Nothing
 End Sub

 標準モジュールには、

 Option Explicit
 Sub sample1()
    Dim cls As Class1
    Set cls = New Class1
    MsgBox "インスタンス作成"
 End Sub
 Sub sample2()
    Dim cls As Class1
    Set cls = New Class1
    MsgBox "インスタンス作成"
    Set cls = Nothing
 End Sub

 sample1とsample2は、同じ動作をしますが、
 Private Sub Class_Terminate()
    bk.ActiveSheet.Range("a1:d10").Value = "owari"
    MsgBox "終わり"
 End Sub

 上記イベントコードの実行が何をトリガーになされているのか
 明確になっているのは、sample2だと思いませんか?
 こういう記述の積み重ねがバグを少なくするコーディングだと思います。

 >私にとっては、Nothingを設定しないことが直接的な問題を引き起こす訳では無い、と云う意味合いの方が大きいです。

 記述したコードを読む人の立場になれば、Nothingの記述はあった方がわかりやすい
 同じような例で、配列の宣言と Eraseステートメントなんてのもありますが、主旨は同じです。
 >今は、最後に書くたびに馬鹿げたことをしているのではないか思う不安の方が大きいです。
 読む立場になれば、これがあると安心すると思いますよ!!

 モジュールレベルでは、Nothingを付けるけど、プロシジャーレベルでは付けない・・。
 プロシジャーレベルの宣言が機能追加や仕様変更などでモジュールレベルに変更された場合、忘れると思いますよ。
 nothingの追加を・・・。それがバグに繋がるかも・・・。

 私も忘れることがあるので自戒の意味も込めて記述しています。

 ichinose


 追伸

 私は、現在、コードを書く仕事は、殆どしていません。が、スタッフが作成したプログラムのバグ修正は
 私がやっています。

 つまり、私以外の人が作ったコードのメンテナンスは、やっているのですが
 この際、こういう後処理が明確になっていれば、読みやすいですよ!!
 オブジェクトでも 配列でも・・・。

 以上、後処理を記述する必要性を私が今、思いつく限り記述して見ました。
 これで分かって頂けないなら、私の力不足ということで今回はこれまでにします。

 今後、私も勉強して分かっていただける記述を模索します。

 が、結論が変わったわけではありません。

後処理を明確にするコーディングポリシーを持つべきです。

 ichinose


 > 上記イベントコードの実行が何をトリガーになされているのか
 > 明確になっているのは、sample2だと思いませんか?

 Terminateのトリガーは、あくまで、これだと思います。
                   ↓
 >オブジェクトに関係する変数すべてに Nothing を設定して、
 >オブジェクトのインスタンスへのすべての参照がメモリから削除されたとき、
 >または最後のオブジェクトへの参照が適用範囲外に出たときに発生します。

 オブジェクト指向の真髄は、仕様をキッチリ作って、あとは各オブジェクトの振舞いに任せる、
 と云うものだと思います。
 上の例で、Nothing代入や、End Subで Terminateイベントを発生させようと意図したのであれば、
 あまり賛成できません。成功するかも知れないし、しないかも知れません。
 (実際は、成功するように作ってあるので成功しますが)、cls はそんなこととはお構いなく、
 愚直に、規定されたタイミングが来ればTerminateを実行するだけだと思います。

 > >今は、最後に書くたびに馬鹿げたことをしているのではないか思う不安の方が大きいです。
 > 読む立場になれば、これがあると安心すると思いますよ!!
  そうですか。私がチェッカーなら、(仕様として本当に不要なら---その見極めはいまだに出来ていないですが、)
 「くだらんこと書くな、モジュール変数が混ざっていたら見つけにくいだろう」って文句を言っちゃうかも知れません。

 平行線になりますので、私のレスも今回かぎりとします。

 私がプログラムを書くのは趣味です。遊びが出発点と云うのはちょっと弱い (^^ゞ

 仕事は、ミスと無駄をなくすことを考える部署にいました(過去形がうれしい)。
 人間に、あれも覚えていろ、これも覚えていろ、と云っても無理なんです。
 必然的に、色々なことをシステム化してきました。

 システム開発においても同じだと思います。昔はプログラマーがやっていたことを
 システム側で吸収してくれていることは多いと思います。
 「初期の頃は、プログラムとデータのメモリー上の住み分けから考えた」って云うSEがいましたからね。
 ガーベッジコレクションなんかも、その延長線上にあるものだと思います。

 >どうせOSがやってくれるから、Closeは省略してもいいや
 OSはその為にあり、省略すべきであると云う時代が来ないとも限りません。

 「分かり切っていることは機械にやらせろ、人間しか出来ないことに人間パワーを使え」
   それが私のシステム化観です。

 (半平太) 2009/03/10 14:11

 なんで、こんなに乖離があるのか、もう一度考えてみました。

 恐らく、プロとアマの違いってことだと思います。

 単発のプロシージャから発展することがそれ程ない(趣味でプログラミングする)人間と、
 色々なスコープの変数が飛び交うプログラムを相手にしている人では、話がかみ合うハズがないです。

 それにしても、この問題に単なる形式論ではないコーディングポリシーが論じられたのは初めてです。
 何か実害が出る(可能性がある)ハズだという論議になることを期待していた身には、意外な展開でした。

 しかし、現場にあるのは、そんなに見通しの悪いプログラム群なのでしょうかねぇ。
 以前、暇つぶしにJAVAの講座を聴きに行ったとき、一つのクラスは30行とか、スクリーン1画面分で作る。
 だらだら長いものは作るな、って云われた記憶があるのですが。。。

 特にコメントは必要ありません。 m(__)m

 (半平太) 2009/03/10 20:29

コメント返信:

[ 一覧(最新更新順) ]


YukiWiki 1.6.7 Copyright (C) 2000,2001 by Hiroshi Yuki. Modified by kazu.