您的位置:首页 > 编程语言 > C语言/C++

C++一些注意点之指针成员管理

2013-08-02 16:58 232 查看
      C++类中经常含有指针,但是如何处理这个问题,本文针对<<C++ Primer>>和<<C++沉思录>>的方法进行了一点小结。本文只是浅尝辄止,深了自己都不懂了,且本文的例子漏洞百出,本文旨在总结这几种处理方法。

 

类中含有指针带来的一些问题

     设计具有指针成员的类时,类设计者必须首先需要决定的是该指针应提供什么行为。将一个指针复制到另一个指针时,两个指针指向同一个对象。当两个指针指向同一对象时,可以使用任一指针改变对象。类似地,很可能一个指针了一个对象时,另一个指针的用户还没有发现。

      通过不同的复制控制策略,可以为指针成员实现不同的行为。通常有以下五种策略(个人之见):

    (1)指针成员采取常规指针行为。这样的类具有所有指针缺限,但是不需要用户编写复制控制程序;

    (2)类采取值行为。复制的时候,另外分配空间,但是值与被复制对象一致;

    (3)采取拥有权转移。即被复制对象释放指针的引用。标准库的auto_ptr;

    (4)实现所谓的“智能指针”。共享对象,但是能防止“悬垂指针”;

    (5)“写时复制”技术。在修改的时候才去重新分配空间。

 

策略一:常规指针行为

      这种方式的赋值操作符/复制构造函数采用系统默认的,两个复制的对象共用相同的空间,这会带来一些析构时遇到的问题。

#include<iostream>
using namespace std;

class HasPtr{
public:
HasPtr(int *p):ptr(p){}
int* getPtr()const
{return ptr;}
void setPtr(int *p)
{ptr = p;}
int& operator*()//返回引用可以对其赋值
{return *ptr;}
const int& operator*()const
{return *ptr;}
int* operator->()
{return ptr;}
const int* operator->()const
{return ptr;}
~ HasPtr(){delete ptr;}
private:
int *ptr;
};

int main()
{
HasPtr p1(new int(5));
HasPtr p2(p1);
*p1 = 12;
cout<<*p1<<endl;//12
cout<<*(p2.operator->())<<endl;//12
system("pause");
return 0;
}


策略二:“值复制”行为

       这种方式在复制的时候,采用“值复制”的方式。即复制的时候不复制空间指针,而是重新分配空间,但是其“值”与被复制的对象“值”一样。一般笔试时,string可以采用这种类型。

/*copyright@ CNV && lsj*/

#include<iostream>
using namespace std;

class HasPtr{
public:
HasPtr(int *p):ptr(p){}
HasPtr(const HasPtr& other):ptr(new int(*other))
{}
HasPtr& operator=(const HasPtr& other)
{
if(&other != this)
*ptr = *other;//如果是数组的话这里,要释放掉原来的值
return *this;
}
int& operator*()//返回引用可以对其赋值
{return *ptr;}
const int& operator*()const
{return *ptr;}
int* operator->()
{return ptr;}
const int* operator->()const
{return ptr;}
~ HasPtr(){delete ptr;}
private:
int *ptr;
};

int main()
{
HasPtr p1(new int(5));
HasPtr p2(p1);
*p2 = 13;
cout<<*p1<<endl;//5
cout<<*p2<<endl;//13
system("pause");
return 0;
}


策略三:拥有权转移行为

      被复制的对象释放对指针的拥有权,由左边对象接管指针的拥有权。标准库auto_ptr采用了这种策略。

/*copyright@ CNV && lsj*/

#include<iostream>
using namespace std;

class HasPtr{
public:
HasPtr(int *p):ptr(p){}
HasPtr(const HasPtr& other)
{
ptr = other.getPtr();
other.setPtr(NULL);
}

HasPtr& operator=(const HasPtr&other)
{
if(&other!=this){
ptr = other.getPtr();
other.setPtr(NULL);
}
return *this;
}
int getPtr()const
{return ptr;}
void setPtr(int *p)
{ptr = p;}
~ HasPtr()
{
if(ptr)delete ptr;
}
private:
int *ptr;
};


策略四:智能指针行为

     这种策略虽然还是采用多个对象共享同一份地址空间,但是通过给类添加计数器,能够有效的防止“悬垂指针”。实现智能指针有两种方案(C++ Primer):计数伙伴类和句柄类。

方案1:设计伙伴计数类。

/*copyright@ CNV && lsj*/

#include<iostream>
using namespace std;

class HasPtr;
class Uptr{//计数伙伴类
friend class HasPtr;
int *ip;//本来应该包含这个指针
size_t use;
Uptr(int *p):ip(p),use(1)
{}
~Uptr(){delete ip;}
};

class HasPtr{
public:
HasPtr(int *p):ptr(new Uptr(p))
{}
HasPtr(const HasPtr& other){
ptr = other.ptr;
++ptr->use;
}
HasPtr operator=(const HasPtr&other){
++other.ptr->use;
if(--ptr->use==0)
delete ptr;
ptr = other.ptr;
return *this;
}
int& operator *()
{ return *(ptr->ip);}

~ HasPtr(){
if(--ptr->use==0)
delete ptr; //将调用伙伴类的析构函数
}
private:
Uptr *ptr;//将int类型的指针封装到伙伴类中
};

int main()
{
HasPtr p1(new int(3));
HasPtr p2 = p1;
*p2 = 5;
cout<<*p1<<endl;//5
system("pause");
return 0;
}


方案2:计数器封装到当前类中,但是计数器use必须采用指针,这样各个指向同一个指针的对象共享同一份空间,都可以去改这个计数器

/*copyright@ CNV && lsj*/

#include<iostream>
using namespace std;

class HasPtr{
public:
HasPtr(int*p):ptr(p),use(new int(1))
{}
HasPtr(constHasPtr& other)
{
ptr= other.ptr;
use= other.use;
++*use;
}
HasPtr&operator=(const HasPtr& other){
++*other.use;
if(--*use==0){
delete ptr;
delete use;
}
ptr= other.ptr;
use= other.use;
return*this;
}
int& operator *()
{
return *ptr;
}
~HasPtr()
{
if(--*use==0)
{
delete ptr;
delete use;
}
}
private:
int *ptr;//所包含元素的指针
//一定要用指针,这样大家共用一份空间,都可以改写
int *use;
};


策略五:写时复制计数

     有时候用户需要对象与对象之间的空间独立,但是每次都复制开销又很大。采用的策略是先不急着复制空间,拖到当另一个类要改写共享空间的时候,复制出来一份改写。

/*copyright@ CNV && lsj*/

#include<iostream>
using namespace std;

class HasPtr{
public:
HasPtr(int*p):ptr(p),use(new int(1))
{}
HasPtr(constHasPtr& other){
ptr= other.ptr;
use= other.use;
++*use;
}
HasPtr& operator=(const HasPtr& other){
++*other.use;
if(--*use==0){
delete ptr;
delete use;
}
ptr= other.ptr;
use= other.use;
return *this;
}
int& operator *()
{
return*ptr;
}
~HasPtr()
{
if(--*use==0)
{
delete ptr;
delete use;
}
}
//这个接口要改写共享空间,此时复制一份改写
void setValue(intval)
{
//判断是不是只有当前对象持有共享空间
//如果是,则不用复制,直接改
if(*use!=1){
--*use;
use= new int(1);
ptr= new int(val);
}
*ptr= val;
}
private:
int *ptr;//所包含元素的指针
//一定要用指针,这样大家共用一份空间,都可以改写
int *use;
};

int main()
{
HasPtr p1(newint(3));
HasPtr p2= p1;
p2.setValue(5);
cout<<*p1<<endl;//5
system("pause");
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息