Skip to content

Commit c207a80

Browse files
committed
relation_toolの不具合修正
CEditDocの破棄がうまくいかない不具合の対策。 事象はMinGWビルドのみで発生。
1 parent 68202f9 commit c207a80

File tree

2 files changed

+67
-32
lines changed

2 files changed

+67
-32
lines changed

sakura_core/util/relation_tool.cpp

Lines changed: 62 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -11,38 +11,53 @@
1111
// CSubject //
1212
// -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- //
1313

14-
CSubject::CSubject()
15-
{
16-
}
14+
CSubject::CSubject() = default;
1715

1816
CSubject::~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+
*/
2727
void 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

5971
CListener::~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+
}

sakura_core/util/relation_tool.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ class CSubject{
3636
public:
3737
//管理用
3838
void _AddListener(CListener* pcListener);
39-
void _RemoveListener(CListener* pcListener);
39+
void _RemoveListener(CListener* pcListener) noexcept;
4040

4141
private:
4242
std::vector<CListener*> m_vListenersRef;
@@ -58,8 +58,11 @@ class CListener{
5858
CSubject* Listen(CSubject* pcSubject); //!< 直前にウォッチしていたサブジェクトを返す
5959
CSubject* GetListeningSubject() const{ return m_pcSubjectRef; }
6060

61+
//管理用
62+
void _EndListen() noexcept;
63+
6164
private:
62-
CSubject* m_pcSubjectRef;
65+
CSubject* m_pcSubjectRef = nullptr;
6366
};
6467

6568
template <class LISTENER> class CSubjectT : public CSubject{

0 commit comments

Comments
 (0)