十年網(wǎng)站開(kāi)發(fā)經(jīng)驗(yàn) + 多家企業(yè)客戶(hù) + 靠譜的建站團(tuán)隊(duì)
量身定制 + 運(yùn)營(yíng)維護(hù)+專(zhuān)業(yè)推廣+無(wú)憂(yōu)售后,網(wǎng)站問(wèn)題一站解決
觀(guān)察者模式(Observer),又叫發(fā)布-訂閱模式(Publish/Subscribe),定義對(duì)象間一種一對(duì)多的依賴(lài)關(guān)系,使得每當(dāng)一個(gè)對(duì)象改變狀態(tài),則所有依賴(lài)于它的對(duì)象都會(huì)得到通知并自動(dòng)更新。
該模式屬于行為型模式。

Subject:抽象主題(抽象被觀(guān)察者),抽象主題角色把所有觀(guān)察者對(duì)象保存在一個(gè)集合里,每個(gè)主題都可以有任意數(shù)量的觀(guān)察者,抽象主題提供一個(gè)或者多個(gè)接口,可以增加和刪除觀(guān)察者對(duì)象。ConcreteSubject:具體主題(具體被觀(guān)察者),該角色將有關(guān)狀態(tài)存入具體觀(guān)察者對(duì)象,在具體主題的內(nèi)部狀態(tài)發(fā)生改變時(shí),給所有注冊(cè)過(guò)的觀(guān)察者發(fā)送通知。Observer:抽象觀(guān)察者,是觀(guān)察者者的抽象類(lèi),它定義了一個(gè)或者多個(gè)更新接口,使得在得到主題更改通知時(shí)更新自己。ConcreteObserver:具體觀(guān)察者,實(shí)現(xiàn)抽象觀(guān)察者定義的更新接口,以便在得到主題更改通知時(shí)更新自身的狀態(tài)。在應(yīng)用觀(guān)察者模式時(shí)需要考慮一下開(kāi)發(fā)效率和運(yùn)行效率的問(wèn)題,程序中包括一個(gè)被觀(guān)察者、多個(gè)觀(guān)察者,將所有的觀(guān)察者都通知到會(huì)花費(fèi)很多時(shí)間。如果考慮到性能問(wèn)題,可以實(shí)現(xiàn)一個(gè)異步非阻塞的觀(guān)察者模式,在每次fire subject的時(shí)候創(chuàng)建一個(gè)新的線(xiàn)程執(zhí)行代碼。
觀(guān)察者模式?jīng)]有相應(yīng)的機(jī)制讓觀(guān)察者知道所觀(guān)察的目標(biāo)對(duì)象是怎么發(fā)生變化的,而僅僅只是知道觀(guān)察目標(biāo)發(fā)生了變化。
#include#include#include#include#includeclass Observer;
typedef std::vector>::iterator Iterator;//迭代器
//抽象被觀(guān)察者
class Subject
{public:
virtual void Attach(std::weak_ptr)=0;//注冊(cè)觀(guān)察者對(duì)象的接口
virtual Iterator Detach(Iterator it)=0;//刪除觀(guān)察者對(duì)象的接口
virtual void notifyObservers()=0;//告知所有觀(guān)察者update
};
//抽象觀(guān)察者
class Observer
{public:
virtual void update()=0;//更新自身狀態(tài)
};
//被觀(guān)察者
class ConcreteSubject :public::Subject
{public:
void Attach(std::weak_ptrs)
{//vector的add是線(xiàn)程安全的
observers_.push_back(s);
}
Iterator Detach(Iterator it)
{//線(xiàn)程不安全,要在臨界區(qū)調(diào)用此接口
return observers_.erase(it);
}
void notifyObservers()
{lock.lock();
Iterator it=observers_.begin();
while(it!=observers_.end())
{//先嘗試將weak_ptr提升為share_ptr
std::shared_ptrobj=it->lock();
if(obj)//提升成功,說(shuō)明該對(duì)象未被其他線(xiàn)程析構(gòu)
{obj->update();//更新
++it;
}
else//提升失敗,說(shuō)明該對(duì)象已被其他線(xiàn)程析構(gòu)
{//從觀(guān)察者集合中將已被析構(gòu)對(duì)象刪除
//因?yàn)榇颂帉儆谂R界區(qū),是線(xiàn)程安全的
it=Detach(it);
}
}
lock.unlock();
}
private:
mutable std::mutex lock;
std::vector>observers_;//觀(guān)察者集合
};
//觀(guān)察者按需求定義即可,需要繼承抽象觀(guān)察者
//以下為例
class Teacher :public::Observer
{public:
void update()
{std::cout<<"Teacher is update"<std::cout<<"Teacher is ~"<public:
void update()
{std::cout<<"Student is update"<std::cout<<"Student is ~"< 測(cè)試
int main()
{ConcreteSubject subject;
std::shared_ptrteacher(new Teacher);
subject.Attach(teacher);
{std::shared_ptrstudent(new Student);
subject.Attach(student);
subject.notifyObservers();
}
subject.notifyObservers();
} 執(zhí)行結(jié)果
Teacher is update
Student is update
Student is ~
Teacher is update
Teacher is ~迭代器失效問(wèn)題分析在學(xué)習(xí)該模型時(shí),遇到了一個(gè)bug,問(wèn)題鎖定在notifyObservers()當(dāng)中,當(dāng)時(shí)的實(shí)現(xiàn)如下
void notifyObservers()
{lock.lock();
Iterator it=observers_.begin();
while(it!=observers_.end())
{std::shared_ptrobj=it->lock();
if(obj)
{obj->update();
}
else
{Detach(it);
}
it++;
}
} 當(dāng)時(shí)執(zhí)行main時(shí),就會(huì)報(bào)段錯(cuò)誤,經(jīng)過(guò)檢查不難發(fā)現(xiàn),問(wèn)題是迭代器失效了
這個(gè)問(wèn)題其實(shí)很好分析,在一順序容器當(dāng)中(vector,queue…等),數(shù)據(jù)是順序存儲(chǔ)的,當(dāng)刪除一個(gè)元素后,內(nèi)存中的數(shù)據(jù)會(huì)往前移動(dòng),以保證數(shù)據(jù)的緊湊。所以刪除一個(gè)元素后,該元素后面的其他元素的地址都會(huì)發(fā)生改變。在刪除操作前所持有的迭代器就會(huì)有失效的可能??聪旅娴睦?。
#include#include#includeusing namespace std;
int main()
{ vectorarr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
vector::iterator it=arr.begin()+3;
cout<<"刪除操作前該迭代器所指向的元素:"< 執(zhí)行結(jié)果如下
刪除操作前該迭代器所指向的元素:
4
進(jìn)行刪除操作
刪除操作前該迭代器所指向的元素:
5添加導(dǎo)致迭代器失效你的添加的操作也是可能導(dǎo)致迭代器失效的。vector的容量是動(dòng)態(tài)的開(kāi)辟的,當(dāng)容量不夠的話(huà),會(huì)進(jìn)行realloc操作進(jìn)行擴(kuò)容,若該數(shù)組的后面的空間不足,realloc函數(shù)會(huì)找一片更大的空間,將原數(shù)據(jù)拷貝進(jìn)去。若在此事件發(fā)生前,獲取一個(gè)迭代器,此事件發(fā)生后,該迭代器會(huì)失效??聪旅胬?/p>
#include#include#includeusing namespace std;
int main()
{ vectorarr;
arr.push_back(1);
arr.push_back(2);
arr.push_back(3);
arr.push_back(4);
arr.push_back(5);
vector::iterator it=arr.begin()+3;
cout<<"此事件發(fā)生前該迭代器所指向的元素:"<arr.push_back(9);
}
cout<<"此事件發(fā)生后該迭代器所指向的元素:"< 執(zhí)行結(jié)果
此事件發(fā)生前該迭代器所指向的元素:
4
此事件發(fā)生后該迭代器所指向的元素:
21854此時(shí)該迭代器就指向一個(gè)未初始化的空間
你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級(jí)流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級(jí)服務(wù)器適合批量采購(gòu),新人活動(dòng)首月15元起,快前往官網(wǎng)查看詳情吧