質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

Q&A

解決済

2回答

4279閲覧

Singletonのテンプレートクラス化試作で出る参照エラーが解決出来ない

Iwan

総合スコア35

Visual Studio

Microsoft Visual StudioはMicrosoftによる統合開発環境(IDE)です。多種多様なプログラミング言語に対応しています。

デザインパターン

デザインパターンは、ソフトウェアのデザインでよく起きる問題に対して、解決策をノウハウとして蓄積し再利用出来るようにした設計パターンを指します。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

DXライブラリ

DXライブラリとは、DirectXを使ったWindowsソフトの開発に必ず付いて回るDirectXやWindows関連のプログラムを使い易くまとめた形で利用できるようにしたC++言語用のゲームライブラリです。

0グッド

0クリップ

投稿2018/11/27 06:27

C++の中でSTL、デザインパターンを勉強中でその一環としてSingletonをテンプレートクラス化して
使ってみる。と言う事をサイト等参考に試作してみたのですが以下のエラーが出ており
調べたりしているのですが解決できず苦慮しており教えて頂きたく思います。

C++

1エラー LNK1120 1 件の未解決の外部参照 DEV_01 C:\MyFile\Sandbox\DEV_01\x64\Debug\DEV_01.exe 1 2エラー LNK2019 未解決の外部シンボル "private: __cdecl SampleObject::SampleObject(void)" (??0SampleObject@@AEAA@XZ) が関数 "public: static class SampleObject * __cdecl Singleton<class SampleObject>::getSingletonPtr(void)" (?getSingletonPtr@?$Singleton@VSampleObject@@@@SAPEAVSampleObject@@XZ) で参照されました。 DEV_01 C:\MyFile\Sandbox\DEV_01\AppSystem.obj 1

【使用環境】
Windows10
VisualStudio2017
DXライブラリ

【サンプルのソースコード】

C++

1<SampleSingleton.h> 2 3template <class _Ty> 4class Singleton 5//class Singleton final // 派生クラスの定義禁止 6{ 7public: 8 typedef _Ty InstanceType; 9 10public: 11/* 12 static void create(){ 13 if (_pInstance == nullptr) { 14 _pInstance = new InstanceType(); 15 } 16 } 17 static void destroy(){ 18 if (_pInstance != nullptr) { 19 delete _pInstance; 20 _pInstance = nullptr; 21 } 22 } 23*/ 24 static InstanceType& getInstanceRef( void ){ 25 return *_pInstance; 26 } 27 static InstanceType* getInstancePtr( void ){ 28 return _pInstance; 29 } 30 static InstanceType* getSingletonPtr( void ){ 31 if ( !_pInstance ) { _pInstance = new InstanceType(); } 32 return _pInstance; 33 } 34 35 // 生成済み? 36 static bool isCreate() { return _pInstance != nullptr; }; 37 // 破棄済み? 38 static bool isDestroy() { return _pInstance == nullptr; }; 39 40private: 41 static InstanceType * _pInstance; //!< 唯一のインスタンス 42 43private: 44 // 禁止 45 Singleton() {} 46 virtual ~Singleton() {} 47 48 Singleton(const Singleton&); /** コピーコンストラクタ(使用禁止) */ 49 Singleton& operator=(const Singleton&); /** 代入演算子(使用禁止) */ 50}; 51 52template <class _Ty> 53typename Singleton<_Ty>::InstanceType* Singleton<_Ty>::_pInstance = nullptr;

C++

1<SampleObject.h> 2 3class SampleObject// : public Singleton<SampleObject > 4{ 5 // SampleObjectのインスタンスを生成する時に、コンストラクタが呼べなかった為friend指定 6 // シングルトンのテンプレート引数に自身を指定したものだけに生成をゆるす 7 friend Singleton<SampleObject>; 8 9public: 10 int m_UseEnable; 11 12private: 13 // コンストラクタ部分をpublicにしてしまうと、SampleObject container; でインスタンスつくれてしまう 14 // 「そのクラスのインスタンスが1つしか生成されないことを保証することができる」 15 // と言うのに反するのでprivateにする必要がある。 16 SampleObject(); // 外部でのインスタンス作成は禁止 17 virtual ~SampleObject(); 18 19}; 20 21inline SampleObject* createObject( void ) 22{ 23 return Singleton<SampleObject>::getSingletonPtr(); 24}

C++

1<main.cpp> 2#include "SampleObject.h" 3#include "DxLib.h" 4 5using CSampleObject= Singleton<SampleObject>; 6 7int WINAPI WinMain( HINSTANCE hInstance, 8 HINSTANCE hPrevInstance, 9 LPSTR lpCmdLine, 10 int nCmdShow ) 11{ 12  // DXライブラリ関係の記述は省略 13 auto result = Singleton<SampleObject>::getSingletonPtr(); 14 15  // DXライブラリ関係の記述は省略 16}

記載してあるコメントで間違っているのがあったり何書いてるのか不明な箇所等
あれば指摘して頂ければ。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

ベストアンサー

こんにちは。

SampleObject(); // 外部でのインスタンス作成は禁止

デフォルト・コンストラクタを宣言していますが、実体の定義がないですよ。
getSingletonPtrから呼び出しているので必要です。

yumetodoさんのは default 指定して実体生成をコンパイラへ指示しているからエラーにならないのだと思います。


しかし、ご提示の実装は任意のクラスをシングルトン化するものですけど、そもそもシングルトンの考え方が「インスタンスを1つしか生成できないことを保証する」目的で使うので、これは意味がないように感じます。
class SampleObject : public Singleton<SampleObject>のようにしてCRTPを併用すると目的を果たすと思います。(boostでよく使われているパターンです。)

投稿2018/11/27 08:15

Chironian

総合スコア23272

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yumetodo

2018/11/27 08:32

無意識レベルで=defaultを追加していたので気が付かなかった・・・。
yumetodo

2018/11/27 08:33

というかそもそもシングルトンを目的としたCRTPを書いたことがないというか。
Iwan

2018/11/27 09:06

回答ありがとうございます。 CRTPに関しては知識が乏しく具体的にどうソースを修正すれば良いのでしょうか?
Iwan

2018/11/27 09:13

またyumetodoさんもこちらでコメントされてるのでこちらでコメントさせて頂きますが public: Singleton(const Singleton&) = delete; /** コピーコンストラクタ(使用禁止) */ Singleton(Singleton&&) = delete; Singleton& operator=(const Singleton&) = delete; /** 代入演算子(使用禁止) */ Singleton& operator=(Singleton&&) = delete; の Singleton(Singleton&&); は何ですか?
Chironian

2018/11/27 10:56

CRTPについてはリンク先の記事を参考にして頂けると、それなりに解説しています。 「2-3.例2:シングルトンの量産」です。
yumetodo

2018/11/27 14:55

copy/move constructorとassgin operatorをdelete指定しています
Iwan

2018/11/28 07:07

リンク先のCRTPサイトを参考にソースを修正しエラーは解消されました。 その中で分からない点がありまして protected: // コンストラクタをprotectedに定義する Singleton() { std::cout << TYPENAME(tDerived) << "()\n"; } と書いてあるのですがprotected:にする理由は何ですか?
yumetodo

2018/11/28 08:18

試しにprivateにしてみればわかると思いますが、基底クラスのコンストラクタを呼べなくなってしまいますよね?
Chironian

2018/11/28 08:42

Iwanさん yumetodoさんのフォローの通りです。 明示的に書いてなくても派生クラスのコンストラクタは基底クラスのコンストラクタを必ず呼びますが、privateだと呼べません。 このようなケースでは派生先を限定したくないのでfriend指定もできません。 外部から使うことを想定しないのでpublicにするのはあまりよくないでしょう。 なのでprotectedです。
guest

0

static InstanceType * _pInstance; //!< 唯一のインスタンス

これをC++17のinline変数にしてあげたほうがいいのと無駄にデストラクタを記述しない以外は特に問題ないと思うんですけどねぇ・・・。それで手元ではエラーないので

https://wandbox.org/permlink/109bKnmQQoD9iDPL

投稿2018/11/27 07:13

yumetodo

総合スコア5850

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問