首页 技术 正文
技术 2022年11月9日
0 收藏 571 点赞 1,899 浏览 6753 个字

  Here are two simple questions.

  Problem A

 #include <string>
include <iostream>
using namespace std; class vehicle
{
public:
vehicle(const string& name);
virtual ~vehicle(){} void PrintOwnerInfo(); private:
string driver_name_;
}; vehicle::vehicle(const string& name):
driver_name_(name){
} void vehicle::PrintOwnerInfo(){
cout<<driver_name_<<endl;
} int main()
{
string driver_name = "Zhou You";
vehicle* pbicycle = new vehicle(driver_name);
pbicycle->PrintOwnerInfo();
return ;
}

  Any problems in the first piece of code?In main function,I produce an vehicle object which is holden by “pbicycle”,then I call PrintOwnerInfo to output the name of the driver.The point is I fail to delete the pointer pbicycle which holds an vehicle object,and this is the most common mistake new programmers always make(it calls memory leak).

  Look at another piece of code.Problem B

class A
{
public:
A();
A(int num);
~A(){} void PrintNum();
private:
int num_;
};A::A():num_(){
}A::A(int num):
num_(num){
}void A::PrintNum(){
cout<<num_<<endl;
}int main()
{
A *pa1 = new A();
pa1->PrintNum(); A *pa2 = pa1;//pa2 point to the same object with pa1
pa2->PrintNum(); delete pa1
pa2->PrintNum();//error happens return ;
}

  In main function,I produce an object of class A,using pa1 to point to it.With a pointer of this object,I call PrintNum function to print the integer.Now that I have pa1,I want to create another pointer pa2 to point to the same object with pa1.The next thing I want to do is to delete pa1.Can I do that?Nooooo.With this inappropriate statement,I transform pa2 to a dangling pointer.The code above is pretty simple and easy,so we can understand it very quickly and find the drawbacks.But in real projects,such mistakes can be easily made and ignored.Is there any good solutions to avoid it?I mean we don’t even need to care about these things.Actually this is part of memory management in C++,we can use smart pointer to help us to handle managing memory issue.

  In the vehicle instance,We can write main function with the smart pointer like this.

int main()
{
string driver_name = "John Zhou";
SPvehicle spbicycle = new vehicle(driver_name);
spbicycle->PrintOwnerInfo(); return ;
}

  ”SPvehicle” is a smart pointer class for vehicle.I do not need to delete it When I finish using this pointer,because this pointer itself has the feature to release its object when it is not useful any more.So how to implement it? Basically,there are two points to take care.

1.”spbicycle” should behave like an vehicle pointer does.It should support both dereferencing(*) operation and indirection(->) operation.

2.It should be able to release the object automatically.

  Check out the code below.

class SPvehicle
{
public:
  SPvehicle(){} 
SPvehicle(vehicle *pvehicle);
~SPvehicle(); vehicle& operator*(){
return *pobjvehicle_;
} vehicle* operator->(){
return pobjvehicle_;
}
private:
vehicle *pobjvehicle_;
};SPvehicle::SPvehicle(vehicle *pvehicle):
pobjvehicle_(pvehicle){
}SPvehicle::~SPvehicle(){
delete pobjvehicle_;
}

  In the SPvehicle class,I overload 2 operators(*,->),then I can use it as a normal vehicle pointer.In the destructor,I delete pobjvehicle_ to release the memory space.

  Class SPvehicle gives us a solution to manage the object automatically,but still remains problem B unsolved.So how to handle the dangling pointer?The object it points to is released by the other pointer,but it is not informed,and this is the direct reason it becomes dangling.For an object,can we remember the amount of the pointer which point to it?With the amount,we are able to know the right time to release the object(the amount decreasing to 0).Let’s try.

class RfCount
{
public:
RfCount(){}
RfCount(unsigned rfc):
rfc_(rfc){
} ~RfCount(){} unsigned AddRef(){
return ++rfc_;
} unsigned CutRef(){
return --rfc_;
}private:
unsigned rfc_;
};class SPA
{
public:
SPA();
SPA(A *pa);
SPA(const SPA &spa);
~SPA(); A& operator*(){
return *pa_;
} A* operator->(){
return pa_;
} SPA& operator=(const SPA &spa);private:
RfCount* reference_count_;
A *pa_;
};SPA::SPA():pa_(NULL),
reference_count_(new RfCount()){
cout<<"default SPA constructor."<<endl;
}SPA::SPA(A* pointera):
pa_(pointera),
reference_count_(new RfCount()){
cout<<"SPA constructor1 adds referencecount by 1."<<endl;
reference_count_->AddRef();
}SPA::SPA(const SPA& spa):
pa_(spa.pa_),
reference_count_(spa.reference_count_){
cout<<"SPA constructor2 adds referencecount by 1."<<endl;
reference_count_->AddRef();
}SPA::~SPA(){
cout<<"SPA destructor cut referencecount by 1."<<endl;
if(reference_count_->CutRef() == ){
cout<<"release the object."<<endl;
delete pa_;
}
}SPA& SPA::operator=(const SPA& spa){
if(this != &spa){
cout<<__FUNCTION__<<" "<<"refcount added by 1."<<endl;
reference_count_ = spa.reference_count_;
reference_count_->AddRef();
pa_ = spa.pa_;
}
return *this;
}void copypointer(SPA& spa){
SPA spa1;
spa1 = spa;
spa1->PrintNum();
}int main()
{
SPA spa1 = new A();
spa1->PrintNum();
copypointer(spa1);
spa1->PrintNum();
return ;
}

  In main function,I produce a smart pointer spa1 at first(reference count is initialized to 1),then use it to call member function of class A which can prove that I can use this smart pointer as a normal A pointer.The next step is to call copypointer() function and it takes spa1 as the argument.In copypointer(),I reproduce a local smart pointer spa2 which is assigned with spa1(reference count up to 2),during the process of assignment,the referencecount is increased to 2.After function copypointer() finishes its task,spa2 just goes out of scope,and SPA destructor is called.In SPA destructor, referencecount is reduced by 1.Back to main funtion,when main ends up,SPA destructor is called again,and reference count is reduced to 0,and that’s exactly the time we need to release A pointer inside class SPA,because there are no pointers referencing this A object.

  OK,for problem A and B I post at the start of this article,we just figure out how to solve or avoid them,but the code look not cool.For problem A and B,we have to write 2 smart pointer classes respectively.so how about a generic class to implement the smart pointer.

class RfCount
{
public:
RfCount(){}
RfCount(unsigned rfc):
rfc_(rfc){
} ~RfCount(){} unsigned AddRef(){
return ++rfc_;
} unsigned CutRef(){
return --rfc_;
}private:
unsigned rfc_;
};template <typename T>
class SP
{
public:
SP();
SP(T *pa);
SP(const SP<T>& sp);
~SP(); T& operator*(){
return *pt_;
} T* operator->(){
return pt_;
} SP& operator=(const SP &sp); unsigned AddRef(){
return reference_count_->AddRef();
} unsigned CutRef(){
return reference_count_->CutRef();
}private:
RfCount* reference_count_;
T *pt_;
};template <typename T>
SP<T>::SP():pt_(NULL),
reference_count_(new RfCount()){
cout<<"default SP constructor."<<endl;
}template <typename T>
SP<T>::SP(T *pt):
pt_(pt),
reference_count_(new RfCount()){
cout<<"SP constructor1 adds referencecount by 1."<<endl;
reference_count_->AddRef();
}template <typename T>
SP<T>::SP(const SP<T>& sp):pt_(sp.pt_),
reference_count_(sp.reference_count_){
cout<<"SP constructor2 adds referencecount by 1."<<endl;
reference_count_->AddRef();
}template <typename T>
SP<T>::~SP(){
cout<<"SP destructor cut referencecount by 1."<<endl;
if(reference_count_->CutRef() == ){
cout<<"release the object."<<endl;
delete pt_;
}
}template <typename T>
SP<T>& SP<T>::operator=(const SP &sp){
if(this != &sp){
reference_count_ = sp.reference_count_;
cout<<__FUNCTION__<<" "<<"refcount added by 1."<<endl;
reference_count_->AddRef();
pt_ = sp.pt_;
}
return *this;
}void copypointer(SP<A>& spa){
SP<A> spa1;
spa1 = spa;
spa1->PrintNum();
}int main()
{
SP<A> spa1 = new A();
spa1->PrintNum();
copypointer(spa1);
spa1->PrintNum();
return ;
}

  Using template,we can write a generic smart pointer class.

  //词汇拙计啊,乃们就将就看吧,有啥问题给俺指正出来呀。

相关推荐
python开发_常用的python模块及安装方法
adodb:我们领导推荐的数据库连接组件bsddb3:BerkeleyDB的连接组件Cheetah-1.0:我比较喜欢这个版本的cheeta…
日期:2022-11-24 点赞:878 阅读:9,104
Educational Codeforces Round 11 C. Hard Process 二分
C. Hard Process题目连接:http://www.codeforces.com/contest/660/problem/CDes…
日期:2022-11-24 点赞:807 阅读:5,581
下载Ubuntn 17.04 内核源代码
zengkefu@server1:/usr/src$ uname -aLinux server1 4.10.0-19-generic #21…
日期:2022-11-24 点赞:569 阅读:6,428
可用Active Desktop Calendar V7.86 注册码序列号
可用Active Desktop Calendar V7.86 注册码序列号Name: www.greendown.cn Code: &nb…
日期:2022-11-24 点赞:733 阅读:6,200
Android调用系统相机、自定义相机、处理大图片
Android调用系统相机和自定义相机实例本博文主要是介绍了android上使用相机进行拍照并显示的两种方式,并且由于涉及到要把拍到的照片显…
日期:2022-11-24 点赞:512 阅读:7,835
Struts的使用
一、Struts2的获取  Struts的官方网站为:http://struts.apache.org/  下载完Struts2的jar包,…
日期:2022-11-24 点赞:671 阅读:4,918