/
Reference.cpp
134 lines (107 loc) · 2.75 KB
/
Reference.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
#include <iostream.h>
// Implements reference counting ( Item 29 ). From More Effective C++
// Not perfect. The program output actually shows the flaw
// The solution is to add a flag to mark it unsharable whenever the
// non-const operator[] is called
// References:
// > Item 8: Understand the different meanings of new and delete.
// > Item 9: Use destructors to avoid memory leak.
// > Item 16: Remember the 80/20 rule.
// > Item 17: ( Lazy Evaluation ).
// > Item 18: Amortize the cost of expected computations.
// > Item 25: Virtualizing constructors and non-member functions.
// > Item 27: Requiring or prohibiting heap based objects.
// > Item 28: Smart pointers.
// > Item 30 (Proxy Classes ) to distinguish read usage from write usage in operator[].
// > Item 32: Program in the future tense.
// > Item 33: Make non-leaf classes abstract.
// > Item E11: Declare a copy constructor and assignment operator for classes with dynamic allocated memory.
// > Item E14: Make sure base classes have virtual destructors.
// > Item E15: Have operator= return a reference to *this.
// > Item E16: Assign to all data members in operator=.
// > Item E17: Check for assignment to self in operator=.
// See also:
// > RCObject.cpp
// > AutoRCObject.cpp
class String
{
public:
String ( const char *initValue = "" );
String ( const String& rhs );
~String();
String& operator=( const String& rhs );
const char& operator [] ( int index ) const;
char& operator[] ( int index );
void Print ( );
private:
struct StringValue
{
int refCount;
char *data;
StringValue( const char *initValue );
~StringValue ( );
};
StringValue *value;
};
String::StringValue::StringValue ( const char *initValue )
:refCount(1)
{
data = new char [strlen (initValue) + 1];
strcpy(data, initValue);
}
String::StringValue::~StringValue()
{
delete [] data;
}
String::String( const char *initValue )
:value ( new StringValue ( initValue ) )
{}
String::String( const String& rhs )
:value ( rhs.value )
{
++value->refCount;
}
String& String::operator=( const String& rhs )
{
if ( value == rhs.value )
return *this;
if ( --value->refCount == 0 )
delete value;
value = rhs.value;
++value->refCount;
return *this;
}
const char& String::operator [] ( int index ) const
{
return value->data[index];
}
char& String::operator[] ( int index )
{
if ( value->refCount > 1 )
{
--value->refCount;
value = new StringValue ( value->data );
}
return value->data[index];
}
void String::Print()
{
cout << value->data;
cout << endl;
}
String::~String()
{
if ( --value->refCount == 0 ) delete value;
}
int main ()
{
String s1("More Effective C++");
char *p = &s1[1];
String s2 = s1;
s1.Print();
s2.Print();
*p = 'x';
s1.Print();
s2.Print();
return 0;
}