初始化
#include <iostream>
#include <string.h>
#include <unistd.h>
using namespace std;
class Person {
public:
Person() {
cout <<"Pserson()"<<endl;
}
~Person()
{
cout << "~Person()"<<endl;
}
void printInfo(void)
{
cout<<"just a test function"<<endl;
}
}
class sp {
private:
Person *p=NULL;
public:
sp() : p(0) {}
sp(Person *other)
{
cout<<"sp(const Person *other)"<<endl;
p = other;
}
sp(int i)
{
cout<<"sp(int="<<i<<")"<<endl;
}
~sp()
{
cout<<"~sp()"<<endl;
if (p)
delete p;
}
Person *operator->()
{
return p;
}
};
void test_func(void)
{
sp i1(5);
sp i2 = 6;
sp s = new Person();
sp s3(new Person) ;
s3->printInfo();
}
int main(int argc, char **argv)
{
test_func();
return 0;
}
初始化变量两种方法:
第一种方法:
class sp;
int k=2;
sp i1(k); //定义sp对象i1,并传入int类型,初始化参数,将调用 sp(int i) 。
第二种方法:
sp i2 = k; ///定义sp对象i2,并传入int类型的k变量,初始化参数,将调用 sp(int i) 。
说明:
- 使用右值传参法,调用对象的对应析构函数来构造对象。
sp s3(new Person) ;
s3->printInfo();
s3中没有printInfo函数,但是sp对象重载了->符号,返回了sp中person类型的私有数据p的指针tmp,指针再调用printInfo函数。
2. 问题推导
void test_func(void)
{
Person *p = new Person();
per.printInfo();
}
int main(int argc, char **argv)
{
int i;
for (i = 0; i < 2; i++)
test_func();
return 0;
}
在 test_func中,使用new Person开辟的内存,没有释放,没有执行Person类的析构函数。
改进1: 使用局部变量
在test_func中,使用局部变量,执行Person类的析构函数。
void test_func(void)
{
Person per;
per.printInfo();
}
int main(int argc, char **argv)
{
int i;
for (i = 0; i < 2; i++)
test_func();
return 0;
}
改进2:在一个类中包含另外一个类指针,在执行这个类析构函数,删除另外一个类指针。
如果
如果函数test_func,是person类指针,则可以在函数test_func申请一个sp类变量A,在sp类中包含person类指针,在释放sp类的析构函数中,如果sp类中的person类指针被赋值,则删除person类指针指向的内存。
class sp {
private:
Person *p;
public:
sp() : p(0) {}
sp(Person *other)
{
cout<<"sp(const Person *other)"<<endl;
p = other;
}
sp(sp &other)
{
cout<<"sp(const Person *other)"<<endl;
p = other.p;
}
~sp()
{
cout<<"~sp()"<<endl;
if (p)
delete p;
}
Person *operator->()
{
return p;
}
};
void test_func(sp &other)
{
sp s = other;
s->printInfo();
}
int main(int argc, char **argv)
{
sp other = new Person();
test_func(other);
cout<<"main() end"<<endl;
return 0;
}
说明:
- main函数
sp other = new Person();==>Person *per1 = new Person(); sp other(per1),声明了一个名为other的sp对象。
2)test_func函数中
sp &other1=other;
sp s = other1; ==>则会调用构造函数
sp(sp &other)
{
cout<<“sp(const Person *other)”<<endl;
p = other.p;
}
sp &other = other1; //引用不能等于临时变量。
const sp &other = other1;
改进3:类的析构函数的参数使用const sp &修饰
修改3:析构函数修改为const sp &,修改代码如下:
class sp {
sp(const sp &other)
{
cout<<"sp(const Person *other)"<<endl;
p = other.p;
}
}
改进4: 引入计数
问题:二次删除指针。
43 ~sp()
44 {
45 cout<<"~sp()"<<endl;
46 if (p)
47 {
48 cout<<"~sp() before delete!"<<endl;
49 delete p;
50 p = NULL;
51 cout<<"~sp() after delete!"<<endl;
52 }
53 }
62 void test_func(sp &other)
63 {
64 sp s = other;
66 s->printInfo();
67 }
68
69 int main(int argc, char **argv)
70 {
71
72 sp other = new Person();
73 test_func(other);
74
75 cout<<"main() end"<<endl;
76
77 return 0;
78 }
在test_func执行结束时候,销毁other,执行sp类析构函数,判断p不为空,则delete p指向的p1;在main函数执行结束后,销毁s1,显然p=123456,不为空,再次销毁p,会产生错误。
解决思路:引入计数,当是最后一个使用者,销毁p。
解决程序如下:
8 class Person {
9 private:
10 int count;
11
12 public:
13 void incStrong(){ count++; }
14 void decStrong(){ count--; }
15 int getStrongCount(){ return count;}
16
17 Person() : count(0){
18 cout <<"Pserson()"<<endl;
19 }
20
21
22 ~Person()
23 {
24 cout << "~Person()"<<endl;
25 }
26 void printInfo(void)
27 {
28 cout<<"just a test function"<<endl;
29 }
30 };
46 sp(const sp &other)
47 {
48 cout<<"sp(const sp &other)"<<endl;
49 p = other.p;
50 p->incStrong();
51 }
52
53 ~sp()
54 {
55 cout<<"~sp()"<<endl;
56
57 if (p)
58 {
59 p->decStrong();
60 //cout<<"~sp() delete1"<<p->getStrongCount<<endl;
61 cout<<"~sp() cout="<<p->getStrongCount()<<endl;
62 if (p->getStrongCount() == 0)
63 {
64 cout<<"~sp() delete"<<endl;
65 delete p;
66 p = NULL;
67 }
68 }
69 }
改进5:计数count封装成一个类
计数count很多类中都用,把count封装成一个基类。
class RefBase {
private:
int count;
public:
RefBase() : count(0) {}
void incStrong(){ count++; }
void decStrong(){ count--; }
int getStrongCount(){ return count;}
};
class Person : public RefBase{
public:
Person() {
cout <<"Pserson()"<<endl;
}
~Person()
{
cout << "~Person()"<<endl;
}
void printInfo(void)
{
cout<<"just a test function"<<endl;
}
};
改进6: 在SP类中,引入模板
有用信息是,SP类属性P指针,P既可以是person类,也可以是其他类。把SP类做成模板。代码如下:
template<typename T>
class sp {
private:
T *p;
public:
sp() : p(0) {}
sp(T *other)
{
cout<<"sp(T *other)"<<endl;
p = other;
p->incStrong();
}
sp(const sp &other)
{
cout<<"sp(const sp &other)"<<endl;
p = other.p;
p->incStrong();
}
~sp()
{
cout<<"~sp()"<<endl;
if (p)
{
p->decStrong();
if (p->getStrongCount() == 0)
{
delete p;
p = NULL;
}
}
}
T *operator->()
{
return p;
}
T& operator*()
{
return *p;
}
};
count操作原子化
如图所示,两个线程操作cout,如果在A线程的count还没写进内存,B线程从内存取的count不是A线程增加过的,就会导致count=2,而不是3.解决办法,最count进行原子操作。
163 template <class T>
164 class LightRefBase
165 {
166 public:
167 inline LightRefBase() : mCount(0) { }
168 inline void incStrong(__attribute__((unused)) const void* id) const {
169 __sync_fetch_and_add(&mCount, 1);
170 }
171 inline void decStrong(__attribute__((unused)) const void* id) const {
172 if (__sync_fetch_and_sub(&mCount, 1) == 1) {
173 delete static_cast<const T*>(this);
174 }
175 }
在Android引入,__sync_fetch_and_add(&mCount, 1)对count进行原子操作。