C++ Handle(句柄) part1
本文是我學(xué)習(xí)C++沉思錄第6章的筆記
本文主要講述了Handle類的概念,定義方法以及寫時(shí)復(fù)制技術(shù)。
?
在前文(Surrogate代理類)的講解中我們了解到了代理的實(shí)現(xiàn)方法.
代理類有很多好處,但是麻煩的是每次都得進(jìn)行復(fù)制.如果該類是經(jīng)常使用并且member很多的話,這樣復(fù)制的消耗是十分客觀的.
因此這里就要介紹另外一種代理類,Handle,也就是句柄類.
?
為何使用句柄類?
首先就是復(fù)制問題.前面有談到,有些類內(nèi)部數(shù)據(jù)很多,采用復(fù)制消耗非常大,這種情況下就必須采用句柄類來進(jìn)行操作.
其次是由于函數(shù)的參數(shù)和返回值都是采用了復(fù)制進(jìn)行自動傳遞.雖然c++中引用可以避免,但是很多情況下返回值采用引用并不明智.
對于采用指針的方式,可以解決問題,但是又會引入調(diào)用者對于動態(tài)管理內(nèi)存的麻煩.而這往往是很多錯(cuò)誤的根源.
?
何為句柄類呢?
句柄類可以理解為采用了引用計(jì)數(shù)的代理類.
其多個(gè)句柄共享了同一個(gè)被代理的類.通過引用計(jì)數(shù)的方式來減少復(fù)制以及內(nèi)存管理.
其行為類似指針,因此也有智能指針之稱,但其實(shí)差別很大.后面會有講述.
?
句柄類例子:
先有一個(gè)簡單的類Point
1 class Point2 {/*{{{*/
3 public:
4 Point():_x(0),_y(0){}
5 Point(int x,int y):_x(x),_y(y){}
6 int x()const {return _x;}
7 void x(int xv) { _x = xv;}
8 int y()const { return _y;}
9 void y(int yv) { _y = yv;}
10 private:
11 int _x;
12 int _y;
13 };/*}}}*/
接下來我們要定義其的Handle類.
我們的Handle類:
1 class Handle2 {
3 public:
4 Handle():up(new UPoint){}
5 Handle(int x,int y):up(new UPoint(x,y)){}
6 Handle(const Point&p):up(new UPoint(p)){}
7 Handle(const Handle &h);
8 ~Handle();
9 Handle& operator=(const Handle &h);
10 int x() const{ return up->p.x(); }
11 int y() const{ return up->p.y(); }
12 Handle& x(int);
13 Handle& y(int);
14
15
16 private:
17 UPoint *up;
18 void allocup();
19 };
這里說明我們的Handle和指針的不同之處.
也許有讀者會對Handle有疑問,為什么不采用operator->來直接操作point呢?
其實(shí)顧慮就是operator->返回的是point的地址.也就是使用者可以輕易的獲得point的地址進(jìn)行操作,這并不是我們想要的.這也就是Handle也pointer不想同的地方.
UPoint是為了采用引用計(jì)數(shù)定義的數(shù)據(jù)結(jié)構(gòu)
2 class UPoint
3 {/*{{{*/
4 friend class Handle;
5
6 Point p;
7 int u;//count
8
9 UPoint():u(0){}
10 UPoint(const Point&pv):p(pv){}
11 UPoint(int x,int y):p(x,y),u(1){}
12 UPoint(const UPoint &up):p(up.p),u(1){}
13 };/*}}}*/
?
對于Handle類的操作,我們要在Handle類進(jìn)行復(fù)制的時(shí)候,累加Handle指向的UPoint的計(jì)數(shù)值
即復(fù)制構(gòu)造函數(shù)以及賦值函數(shù)
1 Handle::Handle(const Handle &h)2 :up(h.up)
3 {
4 ++up->u;
5 }
6
7 Handle& Handle::operator=(const Handle &h)
8 {
9 ++h.up->u;
10 if (--up->u == 0)
11 delete up;
12 up = h.up;
13 return *this;
14 }
而對于析構(gòu)函數(shù),則是減小引用計(jì)數(shù),如果減到0了,就說明沒有其他的Handle指向了UPoint,因此我們要刪除掉.
1 Handle::~Handle()2 {
3 if (--up->u == 0)
4 delete up;
5 }
剩下的就是定義Handle對于Point的操作了.即Handle::x(int xv)和Handle::(int yv)了.
這里有2種寫法.
一種是像指針一樣,對于賦值,就直接修改指向的Point里面的值.這種方法有一個(gè)問題,即所以都指向這個(gè)Point的Handle類獲取的x值都會變化.
代碼:
1 //point like2 Handle& Handle::x(int xv)
3 {
4 up->p.x(xv);
5 return *this;
6 }
7 //point like
8 Handle& Handle::y(int yv)
9 {
10 up->p.y(yv);
11 return *this;
12 }
?
還有一種是寫時(shí)復(fù)制技術(shù),即每次對于共享的Point進(jìn)行修改的時(shí)候都復(fù)制一份新的Point,然后進(jìn)行修改.
這種技術(shù)在Handle中大量采用.在stl中,string也采用了同樣的方法.
其額外開銷很小,而效率也不差.
代碼:
1 void Handle::allocup()2 {
3 if (up->u != 1)
4 {
5 --up->u;
6 up = new UPoint(up->p);
7 }
8 }
9
10 Handle& Handle::x(int xv)
11 {
12 allocup();
13 up->p.x(xv);
14 return *this;
15 }
16
17 Handle& Handle::y(int yv)
18 {
19 allocup();
20 up->p.y(yv);
21 return *this;
22 }
至此,Handle類的第一部分就講完了.
之后會有第二部分的講解.解決了多出了一個(gè)UPoint的麻煩.
總結(jié)
以上是生活随笔為你收集整理的C++ Handle(句柄) part1的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: [c++]代理对象模式
- 下一篇: 设计模式之单例模式(C++代码实现)