第五十五讲 引用计数(2)

关于引用计数大家心里已经有了个底,现在我们来看看下面这个片段:
————————–

SmPt<gameboard>My_Board(gameboard(10,10));


My_Board.get()->SetPiece(6,6,10);


SmPt<gameboard>My_Board2(My_Board);


SmPt<gameboard>My_Board3;


My_Board3 = My_Board;


My_Board3.get()->SetPiece(6,6,25);


————————–

我们创建一个10*10的表格(你要是说他是一个棋盘也是可以的),首先我们在横六平六的位置上放一颗号称是10的棋子,然后我们把这张棋盘带着棋子一同复制给My_Board2,其实,这说起来有些不好理解,也不乎合情理,所以当初我说过,这个棋盘就不该写复制构造函数,但是抛开他是一张棋盘外,他还可以表示其他的很多,如电子表格等等。那么问题来了,我们用的是引用计数的法子,并没有真正的复制,这通常情况是为提高效率,避免不必要的复制拷贝开销,就好比,我们上面这个片段里面,有复制构造(My_Board2(My_Board)),有复制操作符(My_Board3 = My_Board),但是他们的效率非常高,因为他们只是看上去像而已,而且他们不会造成资源的泄露,这就是引用计数的好处,很多程序都应用到他,但是现在大家面临着一个问题,我们重新设置了My_Board3里的棋子,这样本来没什么,但是,我们只想要修改一下My_Board3,并不想修改My_Board和My_Board2,而我们现在却牵一发动全身,怎么办呢?如果说我们一开始就直接来给深度复制,那么又和不用引用计数有啥区别呢?我们可以将复制的时期推迟到需要修改的时候,俗称写时复制,这样一来,并把这个过程推迟到运行期,这多多少少会带来一些开销,但无所谓了,因为这开销并不多。

我现在在想,如果用我们这个棋盘来举这个例子,显然有些大题小作了,很多朋友说为什么不留些练习给大家尝试呢?今天这个正式一个很好的练习,大家可以回去尝试一下,我们用一个简单点的,我们用一个屏幕坐标来举这个例子,假如我们有这么一个类:
——————————-
class Point{
public:

Point();


Point(int x,int y);


Point(const Point&

);


const
int X() const;


const
int Y() const;


Point&

SetX(int x);


Point&

SetY(int y);


~Point();


private:

int mx,my;



};


———————————

为什么选择这个用这个Point?因为想了下,这个类的篇幅不多,也极容易理解,对于教学适合不过了,那么现在我们再来看看下面的程序:
———————————
SmPt<Point>My_Point1(Point(6,8));


SmPt<Point>My_Point2(My_Point1);


My_Point2.get()->SetX(3);


cout<<My_Point1.get()->X()<<endl;


cout<<My_Point2.get()->X()<<endl;


———————————-

我们本是希望得到6和3,但我们却得到的是3和3,为什么呢前面我们已经说过了,我们现在应该是进入正题了,我们再我们智能指针里面添加一个成员函数,用来作写时复制的。
———————————
T* Set()
{

if(count.makeonly())

{

point = new T(*(this->point));


return point;


}

return point;



}
——————————–

现在我们的智能指针里面有两个可以取得指针的成员函数,一个是get(),一个是set(),get()顾名思义,他不能实现复制,所以,当我们只想取得指针信息的时候我们用get,减少复制的开销,提高效率,当我们想要写入信息的时候用set,可以实现复制,开辟内存,构建对象,拷贝数据,如上面所说,这多多少少会带来些额外的开销,但已经将开销降至极限了。现在我们再来使用这个函数看看效果:
——————————–
SmPt<Point>My_Point1(Point(6,8));


SmPt<Point>My_Point2(My_Point1);


My_Point2.get()->SetX(3);


cout<<My_Point1.get()->X()<<endl;


cout<<My_Point2.get()->X()<<endl;


My_Point2.Set()->SetX(15);

//用Set成员函数实现写时复制
cout<<My_Point1.get()->X()<<endl;


cout<<My_Point2.get()->X()<<endl;


——————————–

第五十五讲 引用计数(2)

想要实现gameboard的写诗拷贝,得从gameboard入手,还记得我们有好几个函数没写吗?所以这个问题就留给大家当作练习吧,既然我们现在说了一个关于智能指针的,那么就趁热打铁,我们接下来就模拟一下我们C++的内建指针。



================
回复D直接查看目录

原文始发于微信公众号(

C/C++的编程教室

):第五十五讲 引用计数(2)

|

发表评论