@@ -9,7 +9,6 @@ Copyright: 2005 Robert J. Lang. All Rights Reserved.
99*******************************************************************************/
1010
1111#include < iostream>
12- #include < string>
1312#include < format>
1413
1514#include " tmDpptr.h"
@@ -43,33 +42,142 @@ class B;
4342
4443// Classes A and B hold references to each other.
4544
46- class A : public virtual tmDpptrTarget
47- {
48- public:
49- A () {cout << " member of class A created" << endl;}
50- virtual ~A () {cout << " member of class A deleted" << endl;}
45+ class A : public tmDpptrTarget {
46+ public:
47+ // Default constructor
48+ A () : ab() {
49+ cout << " member of class A created" << endl;
50+ }
51+
52+ // Copy constructor with initialization list
53+ A (const A& other) :
54+ tmDpptrTarget (other),
55+ ab (other.ab) {
56+ cout << " member of class A copied" << endl;
57+ }
58+
59+ // Copy assignment operator
60+ A& operator =(const A& other) {
61+ if (this != &other) {
62+ tmDpptrTarget::operator =(other);
63+ ab = other.ab ;
64+ cout << " member of class A copy assigned" << endl;
65+ }
66+ return *this ;
67+ }
68+
69+ // Move constructor - transfer ownership
70+ A (A&& other) noexcept :
71+ tmDpptrTarget (std::move(other)),
72+ ab (std::move(other.ab)) {
73+ cout << " member of class A moved" << endl;
74+ }
75+
76+ // Move assignment - transfer ownership
77+ A& operator =(A&& other) noexcept {
78+ if (this != &other) {
79+ tmDpptrTarget::operator =(std::move (other));
80+ ab = std::move (other.ab );
81+ cout << " member of class A move assigned" << endl;
82+ }
83+ return *this ;
84+ }
85+
86+ ~A () override { cout << " member of class A deleted" << endl; }
5187 tmDpptr<B> ab;
5288};
5389
5490
55- class B : public virtual tmDpptrTarget
56- {
57- public:
58- B () {cout << " member of class B created" << endl;}
59- virtual ~B () {cout << " member of class B deleted" << endl;}
91+ class B : public tmDpptrTarget { // Remove virtual
92+ public:
93+ // Default constructor
94+ B () { cout << " member of class B created" << endl; }
95+
96+ // Copy constructor - deep copy the tmDpptr
97+ B (const B& other) : tmDpptrTarget(other) {
98+ ba = other.ba ; // tmDpptr has its own copy semantics
99+ cout << " member of class B copied" << endl;
100+ }
101+
102+ // Copy assignment - deep copy the tmDpptr
103+ B& operator =(const B& other) {
104+ if (this != &other) {
105+ tmDpptrTarget::operator =(other);
106+ ba = other.ba ; // tmDpptr has its own copy semantics
107+ cout << " member of class B copy assigned" << endl;
108+ }
109+ return *this ;
110+ }
111+
112+ // Move constructor - transfer ownership
113+ B (B&& other) noexcept : tmDpptrTarget(std::move(other)), ba(std::move(other.ba)) {
114+ cout << " member of class B moved" << endl;
115+ }
116+
117+ // Move assignment - transfer ownership
118+ B& operator =(B&& other) noexcept {
119+ if (this != &other) {
120+ tmDpptrTarget::operator =(std::move (other));
121+ ba = std::move (other.ba );
122+ cout << " member of class B move assigned" << endl;
123+ }
124+ return *this ;
125+ }
126+
127+ ~B () override { cout << " member of class B deleted" << endl; }
60128 tmDpptr<A> ba;
61129
62- void Test () {cout << " test B!" << endl;}
130+ void Test () { cout << " test B!" << endl; }
63131};
64132
65133
66- class D : public virtual tmDpptrTarget
67- {
68- public:
69- D (char * aName) : tmDpptrTarget() {std::format_to_n (mName , 20 , " {}" , aName);
70- cout << mName << " created" << endl;}
71- virtual ~D () {cout << mName << " deleted" << endl;}
72- private:
134+ class D : public tmDpptrTarget {
135+ public:
136+ // Constructor
137+ explicit D (const char * aName) : tmDpptrTarget() {
138+ std::format_to_n (mName , 20 , " {}" , aName);
139+ cout << mName << " created" << endl;
140+ }
141+
142+ // Copy constructor
143+ D (const D& other) : tmDpptrTarget(other) {
144+ std::copy_n (other.mName , 20 , mName );
145+ cout << mName << " copied" << endl;
146+ }
147+
148+ // Copy assignment operator
149+ D& operator =(const D& other) {
150+ if (this != &other) {
151+ tmDpptrTarget::operator =(other);
152+ std::copy_n (other.mName , 20 , mName );
153+ cout << mName << " copy assigned" << endl;
154+ }
155+ return *this ;
156+ }
157+
158+ // Move constructor
159+ D (D&& other) noexcept : tmDpptrTarget(std::move(other)) {
160+ std::copy_n (other.mName , 20 , mName );
161+ other.mName [0 ] = ' \0 ' ; // Clear the source name
162+ cout << mName << " moved" << endl;
163+ }
164+
165+ // Move assignment operator
166+ D& operator =(D&& other) noexcept {
167+ if (this != &other) {
168+ tmDpptrTarget::operator =(std::move (other));
169+ std::copy_n (other.mName , 20 , mName );
170+ other.mName [0 ] = ' \0 ' ; // Clear the source name
171+ cout << mName << " move assigned" << endl;
172+ }
173+ return *this ;
174+ }
175+
176+ ~D () override {
177+ cout << mName << " deleted" << endl;
178+ }
179+
180+ private:
73181 char mName [20 ];
74182};
75183
@@ -105,44 +213,35 @@ int main(void)
105213 cout << " Test of pointer usage:" << endl;
106214
107215 ((B*) c)->Test (); // cast to a pointer
108- (*c).Test (); // dereference
109- c->Test (); // indirect dereference
110-
111- c = 0 ; // Reassigning c removes the last reference to b.
216+ (*c).Test (); // dereference
217+ c->Test (); // arrow operator
112218
113- cout << endl;
219+ // Use smart pointers instead of raw pointers
220+ auto d1 = std::make_unique<D>(" d1" );
221+ tmDpptr<D> rd2 (std::make_unique<D>(" d2" ).release ());
114222
115- // Now try out a tmDpptrArray that automatically removes objects as they are
116- // are deleted.
223+ // No need to delete d1, unique_ptr handles cleanup
117224
225+ // Create test objects and populate array
118226 tmDpptrArray<D> rld; // create a list of references
119227
120- D* d1 = new D (const_cast <char *>(" d1" )); // create a bunch of objects to put into the list
121- D* d2 = new D (const_cast <char *>(" d2" ));
122- D* d3 = new D (const_cast <char *>(" d3" ));
123-
124- tmDpptrTarget* rd1 = d1;
125- tmDpptrTarget* rd2 = d2;
126- tmDpptrTarget* rd3 = d3;
127-
128- rld.push_back (d1); // put them into the list.
129- rld.push_back (d2);
130- rld.push_back (d3);
131- rld.push_back (d1); // also check out effect of multiple references.
132-
133- // Now we'll delete the original objects one by one and watch as they are
134- // automatically removed from the list.
135-
228+ // Create objects with clear ownership
229+ std::unique_ptr<D> up1 (new D (const_cast <char *>(" d1" )));
230+ std::unique_ptr<D> up2 (new D (const_cast <char *>(" d2" )));
231+ std::unique_ptr<D> up3 (new D (const_cast <char *>(" d3" )));
232+
233+ // Add to array without transferring ownership
234+ rld.push_back (up1.get ());
235+ rld.push_back (up2.get ());
236+ rld.push_back (up3.get ());
237+ rld.push_back (up1.get ()); // test multiple references
238+
136239 cout << " Initially rld has " << rld.size () << " elements." << endl;
137-
138- delete d1;
139- cout << " After delete d1 rld has " << rld.size () << " elements." << endl;
140-
141- delete d2;
142- cout << " After delete d2 rld has " << rld.size () << " elements." << endl;
143-
144- delete d3;
145- cout << " After delete d3 rld has " << rld.size () << " elements." << endl;
240+
241+ // Let smart pointers handle cleanup
242+ up1.reset ();
243+ up2.reset ();
244+ up3.reset ();
146245
147246 // Try it again but this time test the clear() command
148247
0 commit comments