【C++ベースの1つ】静的変数の割当てスペースとLNK 2001エラー

2565 ワード

今日は静的変数を用いたときに気づかなかった問題を発見した単例クラスを書きますが、ここでまとめて記録します.
まずこの単例類を見てみましょう.
Singleton.h
#pragma once

class CSingleton
{
public:
	~CSingleton(void);
	static CSingleton* getSingleton();
	int a;
private:
	CSingleton(void);
 static CSingleton* m_Singleton;};
Singleton.cpp
#include "StdAfx.h"
#include "Singleton.h"

CSingleton::CSingleton(void)
{
	a=3;
}
CSingleton::~CSingleton(void)
{
	if(m_Singleton!=NULL)
	{
		delete m_Singleton;
	}
}
CSingleton* CSingleton::getSingleton()
{
	if (m_Singleton==NULL)
	{
		m_Singleton=new CSingleton;
	}
	return m_Singleton;
}
main.cpp
#include "stdafx.h"
#include "Singleton.h"


int _tmain(int argc, _TCHAR* argv[])
{
	std::cout<<CSingleton::getSingleton()->a;
	return 0;
}

実行中、リンクエラーが発生しました.次のようになります.
1>Singleton.obj:error LNK 2001:解析不能外部符号「private:static class CSingleton*CSingleton::m_Singleton」(?m_Singleton@CSingleton@@0PAV1@A) 1>D:\Microsoft Visual Studio 9.0\Projects\TestCpp\Debug\TestCpp.Exce:fatal error LNK 1120:1個の解析不能外部コマンド
気まずいエラーで、コンパイルのエラーは見つけやすいですが、リンクのエラーは気まずいです.特にLNK 2001の原因は様々でしょう.でもやっぱりm_とわかるSingletonという場所で問題が発生しました.これは静的変数です.
static変数の役割と内部メカニズムを理解すると、なぜこのエラーが発生したのかがわかります.
機能:
staticは変数の可視性と記憶方式を制御するために使用される.スタック上の変数は関数の終了後に自動的に解放され,スタックに割り当てられて制御が不便である場合,グローバル変数を定義すると完全に露出し,そのアクセス範囲を破壊し,静的変数は一定範囲内に維持できることを知った.
内部メカニズム:
1.static変数は、オブジェクトではなくクラス全体にサービスするため、クラスに属するオブジェクトが作成されているかどうかにかかわらず、プログラムの実行中に呼び出されるため、静的変数は関数に空間を割り当てたり初期化したりすることはできません.
2.これにより、クラスの外部インタフェースとしてのヘッダファイルとして、クラス宣言がある3つの可能な場所を割り当てることができます.二つ目はクラス定義の内部実装であり、そこにはクラスのメンバー関数定義がある.3つ目は、アプリケーションのmain()関数の前のグローバルデータ宣言と定義です.
3.クラスのヘッダファイル宣言は変数のみを宣言し、スペースを割り当てないため、クラスのヘッダファイルでは定義できません.
4.クラスのヘッダファイル宣言の外で定義する場合、他のクラスが参照するときに繰り返し定義する場合があります.
5.静的変数は、プログラムの静的記憶領域に格納される.
6.ここで例外として、メンバー変数がint,char,boolなどの静的定数タイプの整数クラスである場合、定義なしに宣言で直接初期化できます.(From Effective C++)
解決策
では、LINK 2001の問題はm_であることがわかります.Singletonにはスペースが割り当てられていません.
だからCSingletonでcpp外で静的変数の定義を行えばよい.
CSingleton.cppは以下のように変更され、コンパイルリンクは正常に動作します.
#include "StdAfx.h"
#include "Singleton.h"

CSingleton* CSingleton::m_Singleton=NULL;//     m_Singleton    

CSingleton::CSingleton(void)
{
	a=3;
}
CSingleton::~CSingleton(void)
{
	if(m_Singleton!=NULL)
	{
		delete m_Singleton;
	}
}
CSingleton* CSingleton::getSingleton()
{
	if (m_Singleton==NULL)
	{
		m_Singleton=new CSingleton;
	}
	return m_Singleton;
}