关于含有成员指针的类的复制控制
关于含有成员指针的类的复制控制
一个类中如果含有了指针成员,在不加任何措施的时候,复制类对象是做的位复制操作,即是所谓的浅拷贝,两个对象的指针式一样的值,指向同一块内存区。
这种情况下,当一个对象删除其成员指针指向的内存区后,另一个对象的指针成员指向的内存区也就被释放了。
如果第一个对象析构时删除了这个内存区,那么在第二对象析构时造成同一块内存多次被释放,程序崩溃。
解决这个问题有常规上有两种方法
一是,进行深拷贝,在拷贝构造函数和复制运算符中进行相应的内存分配和复制工作。析构的时候只是各自析构各自的。
二是,采用引用计数手段,在拷贝构造函数和复制运算符中对引用计数进行分析,多个复制对象的指针成员只指向同一个内存区,在最后一个对象析构的时候才最终将这个内存区释放掉。
引用计数的好处是,可以节省内存分配、拷贝、内存释放所带来的效率消耗,以及节省内存。
http://www.cppblog.com/jake1036/archive/2011/05/17/146594.html
浅拷贝
1
#include
<
iostream
>
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 public :
10 str( const char * s = "" )
11 {
12 s_ = new char [strlen(s) + 1 ];
13 if (s_ != 0 )
14 {
15 strcpy(s_, s);
16 }
17 }
18 ~ str()
19 {
20 delete [] s_;
21 }
22 char * s() const
23 {
24 return s_;
25 }
26 };
27
28 ostream & operator << (ostream & out , const str & s)
29 {
30 out << s.s() << endl;
31 return out ;
32 }
33
34 int main()
35 {
36 str s1 = " 123 " ;
37 str s2(s1);
38 cout << s1 << endl;
39 cout << s2 << endl;
40 }
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 public :
10 str( const char * s = "" )
11 {
12 s_ = new char [strlen(s) + 1 ];
13 if (s_ != 0 )
14 {
15 strcpy(s_, s);
16 }
17 }
18 ~ str()
19 {
20 delete [] s_;
21 }
22 char * s() const
23 {
24 return s_;
25 }
26 };
27
28 ostream & operator << (ostream & out , const str & s)
29 {
30 out << s.s() << endl;
31 return out ;
32 }
33
34 int main()
35 {
36 str s1 = " 123 " ;
37 str s2(s1);
38 cout << s1 << endl;
39 cout << s2 << endl;
40 }
深拷贝
1
#include
<
iostream
>
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 public :
10 str( const char * s = "" )
11 {
12 s_ = new char [strlen(s) + 1 ];
13 if (s_ != 0 )
14 {
15 strcpy(s_, s);
16 }
17 }
18 str( const str & s)
19 {
20 s_ = new char [strlen(s.s_) + 1 ];
21 if (s_ != 0 )
22 {
23 strcpy(s_, s.s_);
24 }
25 }
26 str & operator = ( const str & s)
27 {
28 if ( this != & s)
29 {
30 delete [] s_;
31 s_ = new char [strlen(s.s_) + 1 ];
32 if (s_ != 0 )
33 {
34 strcpy(s_, s.s_);
35 }
36 }
37 return * this ;
38 }
39 ~ str()
40 {
41 delete [] s_;
42 }
43 char * sr() const
44 {
45 return s_;
46 }
47 };
48
49 ostream & operator << (ostream & out , const str & s)
50 {
51 out << s.sr() << endl;
52 return out ;
53 }
54
55 int main()
56 {
57 str s1 = " 123 " ;
58 str s2(s1);
59 cout << s1 << endl;
60 cout << s2 << endl;
61 }
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 public :
10 str( const char * s = "" )
11 {
12 s_ = new char [strlen(s) + 1 ];
13 if (s_ != 0 )
14 {
15 strcpy(s_, s);
16 }
17 }
18 str( const str & s)
19 {
20 s_ = new char [strlen(s.s_) + 1 ];
21 if (s_ != 0 )
22 {
23 strcpy(s_, s.s_);
24 }
25 }
26 str & operator = ( const str & s)
27 {
28 if ( this != & s)
29 {
30 delete [] s_;
31 s_ = new char [strlen(s.s_) + 1 ];
32 if (s_ != 0 )
33 {
34 strcpy(s_, s.s_);
35 }
36 }
37 return * this ;
38 }
39 ~ str()
40 {
41 delete [] s_;
42 }
43 char * sr() const
44 {
45 return s_;
46 }
47 };
48
49 ostream & operator << (ostream & out , const str & s)
50 {
51 out << s.sr() << endl;
52 return out ;
53 }
54
55 int main()
56 {
57 str s1 = " 123 " ;
58 str s2(s1);
59 cout << s1 << endl;
60 cout << s2 << endl;
61 }
引用计数
引用计数的实现是通过在类对象中增加一个指向 int 型的指针,这个指针指向的那个 int 即是计数,记录指针指向的那块内存被几个对象共用着。
采用引用计数,在构造函数、析构函数、拷贝构造函数、复制运算符中,都要对这个指向 int 的指针进行操作,并且需要判断指针指针指向 int 的变化情况,当为 0 时,则要释放掉指针指向的内存。
1
#include
<
iostream
>
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 int * pcount_;
10 public :
11 str( const char * s = "" )
12 {
13 s_ = new char [strlen(s) + 1 ];
14 if (s_ != 0 )
15 {
16 strcpy(s_, s);
17 pcount_ = new int ;
18 if (pcount_ != 0 )
19 {
20 * pcount_ = 1 ;
21 }
22 }
23 }
24 str( const str & s)
25 {
26 s_ = s.s_;
27 pcount_ = s.pcount_;
28 ++ ( * pcount_);
29 }
30 str & operator = ( const str & s)
31 {
32 if ( this != & s)
33 {
34 -- ( * pcount_);
35 if ( * pcount_ == 0 )
36 {
37 if (s_ != 0 )
38 {
39 delete [] s_;
40 s_ = 0 ;
41 }
42 delete pcount_;
43 pcount_ = 0 ;
44 }
45 s_ = s.s_;
46 pcount_ = s.pcount_;
47 ++ ( * pcount_);
48 }
49 return * this ;
50 }
51 ~ str()
52 {
53 -- ( * pcount_);
54 if ( * pcount_ == 0 )
55 {
56 // cout << "test" << endl;
57 if (s_ != 0 )
58 {
59 delete [] s_;
60 s_ = 0 ;
61 }
62 delete pcount_;
63 pcount_ = 0 ;
64 }
65 }
66 char * sr() const
67 {
68 return s_;
69 }
70 };
71
72 ostream & operator << (ostream & out , const str & s)
73 {
74 out << s.sr() << endl;
75 return out ;
76 }
77
78 int main()
79 {
80 str s1 = " 123 " ;
81 str s2(s1);
82 cout << s1 << endl;
83 cout << s2 << endl;
84 }
85
2 #include < cstring >
3 using namespace std;
4
5 class str
6 {
7 private :
8 char * s_;
9 int * pcount_;
10 public :
11 str( const char * s = "" )
12 {
13 s_ = new char [strlen(s) + 1 ];
14 if (s_ != 0 )
15 {
16 strcpy(s_, s);
17 pcount_ = new int ;
18 if (pcount_ != 0 )
19 {
20 * pcount_ = 1 ;
21 }
22 }
23 }
24 str( const str & s)
25 {
26 s_ = s.s_;
27 pcount_ = s.pcount_;
28 ++ ( * pcount_);
29 }
30 str & operator = ( const str & s)
31 {
32 if ( this != & s)
33 {
34 -- ( * pcount_);
35 if ( * pcount_ == 0 )
36 {
37 if (s_ != 0 )
38 {
39 delete [] s_;
40 s_ = 0 ;
41 }
42 delete pcount_;
43 pcount_ = 0 ;
44 }
45 s_ = s.s_;
46 pcount_ = s.pcount_;
47 ++ ( * pcount_);
48 }
49 return * this ;
50 }
51 ~ str()
52 {
53 -- ( * pcount_);
54 if ( * pcount_ == 0 )
55 {
56 // cout << "test" << endl;
57 if (s_ != 0 )
58 {
59 delete [] s_;
60 s_ = 0 ;
61 }
62 delete pcount_;
63 pcount_ = 0 ;
64 }
65 }
66 char * sr() const
67 {
68 return s_;
69 }
70 };
71
72 ostream & operator << (ostream & out , const str & s)
73 {
74 out << s.sr() << endl;
75 return out ;
76 }
77
78 int main()
79 {
80 str s1 = " 123 " ;
81 str s2(s1);
82 cout << s1 << endl;
83 cout << s2 << endl;
84 }
85