1111// CSubject //
1212// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
1313
14- CSubject::CSubject ()
15- {
16- }
14+ CSubject::CSubject () = default;
1715
1816CSubject::~CSubject ()
1917{
2018 // リスナを解除
21- for ( int i= 0 ;i<( int ) m_vListenersRef.size ();i++) {
22- m_vListenersRef[i]-> Listen ( nullptr );
19+ while (! m_vListenersRef.empty ()) {
20+ _RemoveListener ( m_vListenersRef. back () );
2321 }
24- m_vListenersRef.clear ();
2522}
2623
24+ /* !
25+ * リスナーを追加する
26+ */
2727void CSubject::_AddListener (CListener* pcListener)
2828{
29+ // NULLは追加できない
30+ assert (pcListener);
31+
2932 // 既に追加済みなら何もしない
30- for (int i=0 ;i<(int )m_vListenersRef.size ();i++){
31- if (m_vListenersRef[i]==pcListener){
32- return ;
33- }
33+ if (auto found = std::find (m_vListenersRef.cbegin (), m_vListenersRef.cend (), pcListener); found != m_vListenersRef.cend ()) {
34+ return ;
3435 }
36+
3537 // 追加
3638 m_vListenersRef.push_back (pcListener);
3739}
3840
39- void CSubject::_RemoveListener (CListener* pcListener)
41+ /* !
42+ * リスナーを削除する
43+ */
44+ void CSubject::_RemoveListener (CListener* pcListener) noexcept
4045{
46+ // NULLは追加できないので、削除も想定しない
47+ assert (pcListener);
48+
49+ // 削除前のリスナー数を記録
50+ const auto llisteners = m_vListenersRef.size ();
51+
4152 // 配列から削除
42- for (int i=0 ;i<(int )m_vListenersRef.size ();i++){
43- if (m_vListenersRef[i]==pcListener){
44- m_vListenersRef.erase (m_vListenersRef.begin ()+i);
45- break ;
53+ if (auto found = std::find (m_vListenersRef.begin (), m_vListenersRef.end (), pcListener); found != m_vListenersRef.end ()) {
54+ // 確実に解除するため、リスナー側の終了メソッドを呼び出す
55+ pcListener->_EndListen ();
56+
57+ // リスナー数が代わってないときだけ削除に進む
58+ if (llisteners == m_vListenersRef.size ()) {
59+ // リスナー配列から削除
60+ m_vListenersRef.erase (found);
4661 }
4762 }
4863}
@@ -51,31 +66,48 @@ void CSubject::_RemoveListener(CListener* pcListener)
5166// CListener //
5267// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
5368
54- CListener::CListener ()
55- : m_pcSubjectRef(nullptr )
56- {
57- }
69+ CListener::CListener () = default;
5870
5971CListener::~CListener ()
6072{
61- Listen ( nullptr );
73+ _EndListen ( );
6274}
6375
64- CSubject* CListener::Listen (CSubject* pcSubject)
76+ /* !
77+ * 監視を開始する
78+ */
79+ CSubject* CListener::Listen (
80+ CSubject* pcSubject // !< [in] 監視するサブジェクト。NULLで監視終了
81+ )
6582{
66- CSubject* pOld = GetListeningSubject ();
83+ // 操作前の参照を取得
84+ auto pOld = GetListeningSubject ();
6785
68- // 古いサブジェクトを解除
69- if (m_pcSubjectRef){
70- m_pcSubjectRef->_RemoveListener (this );
71- m_pcSubjectRef = nullptr ;
72- }
86+ // 古いサブジェクトを解放
87+ _EndListen ();
7388
7489 // 新しく設定
75- m_pcSubjectRef = pcSubject;
76- if (m_pcSubjectRef){
77- m_pcSubjectRef->_AddListener (this );
90+ if (pcSubject) {
91+ // サブジェクト側にリスナー追加を要求する
92+ pcSubject->_AddListener (this );
93+
94+ // 参照を保存
95+ m_pcSubjectRef = pcSubject;
7896 }
7997
8098 return pOld;
8199}
100+
101+ /* !
102+ * 監視を終了する
103+ */
104+ void CListener::_EndListen () noexcept
105+ {
106+ if (auto pcSubject = m_pcSubjectRef) {
107+ // 構造的に再帰呼出なので、先に参照を消しておく
108+ m_pcSubjectRef = nullptr ;
109+
110+ // サブジェクト側にリスナー削除を要求する
111+ pcSubject->_RemoveListener (this );
112+ }
113+ }
0 commit comments