閑古鳥

オールドプログラマの日記。プログラミングとか病気(透析)の話とか。

NULLポインタの参照

少し前にあった話。とあるポインタ変数の中身が 0(NULL) である時に、そのメンバを安全に参照する方法。というかなんというか。

簡単な Singleton クラスを作成して、そのクラスのインスタンスは一番最初に参照された時に生成するようにしていました。書いたコードは以下のようなもの。昔ここに載せたのと同じもの。

#include <iostream>

class Singleton
{
public:
  static Singleton& Instance()
  {
    static Singleton theInstance;
    return theInstance;
  }

  void Execute()
  {
    std::cout << m_msg << std::endl;
  }
private:
  const char* m_msg;
  
private:
  Singleton() : m_msg("Execute") {}
  Singleton(const Singleton&);
  Singleton& operator=(const Singleton&);
};

特に問題も無く動いていたのですが、ある日このインスタンスの生成を決まったタイミングで行いたいと言う事になり、インスタンスを静的なポインタ変数に置き換え、 Construction メソッドを追加してそこで new するように変更しました。後は好きなタイミングで呼べばいい、ということにしたのですが、インスタンスを生成する前に使用したがために Access Violation が発生すると言う問題が。

しかしこのインスタンスを生成する前の変数の値が 0 であることが決まっていたため、下記のように書き換え、事なきを得ました。

#include <iostream>
#include <cstdlib>

class Singleton
{
public:
  static void Construction()
  {
    if(!m_pInst)
    {
        m_pInst = new Singleton();
        ::atexit(Destroy);
    }
  }
  
  static Singleton& Instance()
  {
    return *m_pInst;
  }

  void Execute()
  {
    if(this) //※
    {
        std::cout << m_msg << std::endl;
    }
  }
private:
  const char* m_msg;
  
  static Singleton* m_pInst;
  static void Destroy()
  {
    delete m_pInst;
  }
  
private:
  Singleton() : m_msg("Execute") {}
  Singleton(const Singleton&);
  Singleton& operator=(const Singleton&);
};
Singleton* Singleton::m_pInst = 0;

たとえクラスのポインタ変数が 0 であったとしても、 this に触らない限りは安全であるため、 if(this) で生成済みかどうかを確認することで、生成前のメソッド呼び出しにも対応できる、と。

まあ、こんなコード、普通は書くべきではありませんが、知っていると役に立つ事もあるかも、ということで。 MFC では割と使われているようです。