2020/02/28 新型コロナとIT化
2020/02/22 Multi Function Alarm Ver. up to 2.02
2020/02/19 民法改正とコンピューター
2020/02/15 C++ スマートポインターについて
2020/02/08 a! Menu Archiver Ver. up to 2.02
2020/02/02 C++ のコピー、new、配列化禁止
新型コロナウイルス(COVID-19)の感染力は高い。
SARS, MERS は感染力がそれほど高くないので封じ込めに成功したが、
今回のコロナウイルスは検疫官や厚労省職員の複数感染からもわかるように、
想定を超す感染力である。
それに対して安倍総理の対応は「かっこつけてるだけ」ように見えるのだが、
この話をしだすと本題からそれてしまうので止めておく。
新型コロナ関係で「テレワーク」とか「キャッシュレス」という、
キーワードが台頭してきたのにはちょっと驚いた。
人が集まることを避けるためにテレワークを行い、
お札からの感染を防ぐためにキャッシュレスを行う。
これらが発達してきたのは新型コロナの準備だったのではと思った。
令和2年西暦2020年2月22日 Multi Function Alarm をバージョンアップしました。
おめでたいかどうかわかりませんが、この「2」が多いときに Ver.2.02(これも「2」が多い)になりました。
Ver.2.22にすることも考えましたが、わざとらしいので止めました。
バージョンアップ内容は以下の通りです。
Ver.2.02 2020/02/22
2番目の変更はスクリーンセーバーの設定変更ではインパクトが少ないので思い切って実行するように変更してみました。
3番目と4番目の変更は文字通りです。
5番目の変更はここにあります。
詳細はそのうち...といつもは言っていましたが、
実は既に解説を始めています。ここ辺りからです。
民法改正の勉強をしている。
民法はほぼその国の道徳観を表すといってもいい法律で、
明治時代に制定されて以来内容が大きくいじられることはなかったが、
今回の改正は大幅である。
変更の内容は、道徳観が変ったというよりは、
ほぼ判例の部分を文書化して付け加えたという形である。
その法律の中にコンピュータ用語が結構登場してきた。
まずは548条の3第2項に「通信障害」というのが定義なしで登場する。
次には548条の4第2項に「インターネット」というのが定義なしで登場する。
その次に398条の2第3項に「電子記録債権」というのが登場する。
定義は「電子記録債権法」の中にあり、398条の3第2項で参照されている。
一番参照が多いのは「電磁的記録」で151条第4項で定義され、
446条、472条の4第5項、587条の2第4項で参照されている。
内容は民法の中で「書面でされなければならない」ものに対して
「電磁的記録は書面でされたこととみなす」というものである。
時代の流れだなと思った。
ここ ではデストラクターがどこで働くかを見てみたが、
そのソースの中で new によりメモリーを確保した場合、
どこかで delete または delete[] が必要になる。
それも1つとは限らない。
a, b の変数に対して、return や break があると増えてしまい、3つずつになってしまう。
これでは、delete または delete[] を忘れてしまいそうになる。
いい考えがないかどうか?!
コンストラクターで new をして、デストラクターで delete 若しくは delete[] をするようなクラスの変数を作ればいい。
その変数がスコープ外になる(例えば return や break の実行)時には自動でデストラクターが働くようになる。
これをスマートポインターというのだが、C++ 標準の std::auto_ptr とかでは、配列ができない。
そもそも new をするのは動的に配列を確保する場合がほとんどである。
よってその部分は自作することにした。
全文を公開することにしたので、以下のソースを見てもらいたい。
//--------------------------------------------------------------------------- #pragma once //--------------------------------------------------------------------------- #include <windows.h> #include "Inhibit.h" //--------------------------------------------------------------------------- template <typename Obj> class CArray final { // // コンストラクタ、デストラクタ public: explicit CArray(int n) : nsize(n) { Objs = new Obj[n];}; ~CArray(void){ delete[] Objs;}; COPYINHIBIT(CArray<Obj>) NEWINHIBIT // // 変数 private: const int nsize; Obj* Objs; // // 関数 public: inline Obj& operator[](int ind) const { return Objs[ind];}; inline Obj* const pobj(void) const { return Objs;}; inline const int size(void) const { return nsize;}; }; //--------------------------------------------------------------------------- template <typename Obj> class CArrayPtr final { // // コンストラクタ、デストラクタ public: explicit CArrayPtr(Obj* pObj = NULL) : Objs(pObj){}; ~CArrayPtr(void){ delete[] Objs;}; COPYINHIBIT(CArrayPtr<Obj>) NEWINHIBIT // // 変数 private: Obj* Objs; // // 関数 public: CArrayPtr<Obj>& operator=(Obj* ptr){ if ( ptr == Objs ) return *this; delete[] Objs/*置換*/; Objs = ptr; return *this;}; inline Obj& operator[](int ind) const { return Objs[ind];}; inline Obj* const pobj(void) const { return Objs;}; inline Obj** const ppobj(void){ return &Objs;}; }; //--------------------------------------------------------------------------- template <typename Obj> class CNewPtr final { // // コンストラクタ、デストラクタ public: explicit CNewPtr(Obj* pObj = NULL) : pObj(pObj){}; ~CNewPtr(void){ delete pObj;}; COPYINHIBIT(CNewPtr<Obj>) NEWINHIBIT // // 変数 private: Obj* pObj; // // 関数 public: CNewPtr<Obj>& operator=(Obj* ptr){ if ( ptr == pObj ) return *this; delete pObj/*置換*/; pObj = ptr; return *this;}; Obj* const operator->(void) const { return pObj;}; // operator* は必要が無かったので作らなかった inline Obj* const pobj(void) const { return pObj;}; }; //--------------------------------------------------------------------------- |
これを使うとここのソースが以下のように書ける。
class T1 { T1(...); ... } class T2 { T2(); ... const T2& operator+(const T2& a); } main() { ... for(...){ CNewPtr<T1> a(new T1(...)); CArray<T2> b(...); ... T2 c, d, e; T2 f = c + d + e; ... if ( ... ) return; ... if ( ... ) break; ... if ( ... ) throw("例外を投げますよ"); ...} ... } |
delete や delete[] が全くいらなくなる。
これらがどれだけ役に立っているか、公開しているソフトの中を検索してみた。
CArrayPtr の使用例についてはそのうち。
今日付けで a! Menu Archiver をバージョンアップしました。バージョンアップ内容は以下の通りです。
Ver.2.02 2020/02/08
3番目の変更は、文字通りですが、前バージョンでデフォールト値を変えた時に
設定画面で一番上にデフォールト値が来るようにするのを忘れていました。その修正です。
4番目の変更はここにあります。
詳細はそのうち...
C++ では、コピー、new、配列化禁止が簡単にできる。
以下のマクロを見てもらいたい。
// // 原則として class 用 // Obj クラスを関数の引数や戻り値とする場合やコピーのための代入を禁止する // Obj のポインターはOK // Obj の移動もついでに禁止する #define COPYINHIBIT(Obj) \ Obj(const Obj&) = delete; \ Obj& operator=(const Obj&) = delete; \ Obj(Obj&&) = delete; \ Obj& operator=(Obj&&) = delete; // // 原則として struct 用 深いコピーが必要な場合入れておく #define STRUCTCOPYINHIBIT(Obj) \ Obj(void){}; \ Obj(const Obj&) = delete; \ Obj& operator=(const Obj&) = delete; \ Obj(Obj&&) = delete; \ Obj& operator=(Obj&&) = delete; // // 移動のみ禁止する(使えるところが無かった) //#define MOVEINHIBIT(Obj) \ // Obj(Obj&&) = delete; \ // Obj& operator=(Obj&&) = delete; // // new を禁止、即ち delete も禁止 #define NEWINHIBIT \ void* operator new(size_t) = delete; \ void* operator new[](size_t) = delete; \ void operator delete(void*) = delete; \ void operator delete[](void*) = delete; // // new[] 、delete[] を禁止 #define ARRAYINHIBIT \ void* operator new[](size_t) = delete; \ void operator delete[](void*) = delete; // // new[] 、delete[] を許す(使えるところが無かった) //#define NEWONLYINHIBIT \ // void* operator new(size_t) = delete; \ // void operator delete(void*) = delete; |
これをクラスの定義の中に入れておけばOK
これがどれくらい役立っているか見てみよう。共通ライブラリーの中のクラスで調べてみた。
そもそもポインターより大きい領域を取るオブジェクトは、関数の引数にする場合ポインターか参照型にする。
関数の戻り値の場合はオブジェクトそのものを返す事もあるにはあるが例はなかった。
よってコピーの必要性はあまりない。
必要ができた時はコピーコンストラクターと operator= を定義するというスタンスにしている。
COPYINHIBIT も STRUCTCOPYINHIBIT も入れていない2個のオブジェクトに MOVEINHIBIT を入れてみたが、
戻り値のところで && が付いたコンパイルエラーになった。という事は戻り値は std::mode で実行している?!
それは最適化の理にかなっている。
new の場合は確実に new は不要であるとわかっている場合は、NEWINHIBIT にしている。
コンテナー関連に、NEWINHIBIT や ARRAYINHIBIT がない理由は、
コンテナーをネストするために new したり、配列にする場合があるからである。
共通ライブラリ以外でも現在の状態で数だけざっと検索してみたので、結果のみをここに書く。