C++ Library Extensions 2022.12.09
To help learn modern C++ programming
021-emplace.cpp
Go to the documentation of this file.
1#include <tpf_output.hpp>
2#include <cstdlib>
3
6
7template<typename ElementType>
9{
10private:
11 size_t m_size;
12 ElementType *m_ptr;
13
14 void free_memory()
15 {
16 if (this->m_size != 0 || m_ptr != nullptr)
17 {
18 delete[] m_ptr;
19 this->m_ptr = nullptr;
20 this->m_size = 0;
21 }
22 }
23
24 void invalidate()
25 {
26 this->m_ptr = nullptr;
27 this->m_size = 0;
28 }
29
30public:
31 size_t size() const { return this->m_size; }
32
33 void resize(size_t count)
34 {
35 if(count < 1)
36 Tpf_ThrowDebugException("count should be greater than 0");
37 else if(count == this->m_size)
38 return;
39 else
40 {
41 // free existing memory
42 this->free_memory();
43
44 try
45 {
46 this->m_size = count;
47 this->m_ptr = new ElementType[this->m_size];
48 }
49 catch(...)
50 {
51 Tpf_ThrowDebugException("Dynamic Allocation Failed");
52 }
53 }
54 }
55
56 // this is dangerous practice
57 // if dynamic allocation fails,
58 // this constructor throws std::bad_alloc exception
59 dynamic_array(size_t size = 1)
60 : m_size{size}
61 {
62 stream << "Default constructor called" << endl;
63
64 try
65 {
66 this->m_ptr = size > 0 ? new ElementType[size] : nullptr;
67 }
68 catch(...)
69 {
70 // it reports details about allocation failture
71 Tpf_ThrowDebugException("Dynamic Allocation Failed");
72 }
73 }
74
75 // if dynamic allocation fails,
76 // it throws exception
77 dynamic_array(const dynamic_array &right_hand_side) :
78 m_size{right_hand_side.m_size}
79 {
80 stream << "Copy constructor called" << endl;
81
82 try
83 {
84 this->m_ptr = this->m_size > 0 ? new ElementType[this->m_size] : nullptr;
85
86 if (m_size > 0)
87 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
88 }
89 catch(...)
90 {
91 // it reports details about allocation failture
92 Tpf_ThrowDebugException("Dynamic Allocation Failed");
93 }
94
95 }
96
97 ElementType *operator&() { return this->m_ptr; }
98
99 ElementType &operator[](size_t index) { return this->m_ptr[index]; }
100
101 const ElementType &operator[](size_t index) const { return this->m_ptr[index]; }
102
103 ElementType &at(size_t index)
104 {
105 if (index < this->m_size && this->m_ptr != nullptr)
106 return this->m_ptr[index];
107 else
108 Tpf_ThrowDebugException("Index Out of Range");
109 }
110
111 const ElementType &at(size_t index) const
112 {
113 if (index < this->m_size && this->m_ptr != nullptr)
114 return this->m_ptr[index];
115 else
116 Tpf_ThrowDebugException("Index Out of Range");
117 }
118
119 // if allocation fails,
120 // it can throw std::bad_alloc exception
121 dynamic_array &operator=(const dynamic_array &right_hand_side)
122 {
123 stream << "Copy assignment operator() called" << endl;
124
125 // this code is wrong, because address of operator&()
126 // is defined for class dynamic_array,
127 // so, we cannot use the following code any longer
128 // if(this != &right_hand_side)
129
130 if (this != std::addressof(right_hand_side))
131 {
132 if (this->m_size == right_hand_side.m_size)
133 {
134 // we do not need to reallocate memory
135 // and also, we do not need to free memory
136 // this->free_memory()
137
138 if (m_size > 0)
139 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
140 }
141 else
142 {
143 // we have free existing memory
144 this->free_memory();
145 this->m_size = right_hand_side.m_size;
146
147 if (this->m_size > 0)
148 {
149 try
150 {
151 // and we have to reallocate new memory
152 this->m_ptr = new ElementType[this->m_size];
153 std::memcpy(this->m_ptr, right_hand_side.m_ptr, m_size * sizeof(ElementType));
154 }
155 catch(...)
156 {
157 // it reports details about allocation failture
158 Tpf_ThrowDebugException("Dynamic Allocation Failed");
159 }
160 }
161 }
162 }
163
164 return *this;
165 }
166
167 dynamic_array(dynamic_array &&right_hand_side) noexcept
168 : m_size{right_hand_side.m_size},
169 m_ptr{right_hand_side.m_ptr}
170 {
171 stream << "Move constructor called" << endl;
172
173 // IMPORTANT: invalidate right_hand_side
174 // after move, right_hand_side is invalide
175 // so, we should NOT access to right_hand_side after move operation
176 right_hand_side.invalidate();
177 }
178
179 dynamic_array &operator=(dynamic_array &&right_hand_side) noexcept
180 {
181 stream << "Move assignment operator() called" << endl;
182
183 if (this != std::addressof(right_hand_side))
184 {
185 // delete existing memory
186 this->free_memory();
187 this->m_size = right_hand_side.m_size;
188 this->m_ptr = right_hand_side.m_ptr;
189
190 // IMPORTANT: invalidate right_hand_size after move assignment
191 // since after move operation, right_hand_side is invalid
192 // so, we should NOT access to right_hand_side after move operation
193 right_hand_side.invalidate();
194 }
195
196 return *this;
197 }
198
200 {
201 stream << "Destructor called" << endl;
202
203 this->free_memory();
204 }
205
206 friend std::ostream& operator<<(std::ostream& os, const dynamic_array& da)
207 {
208 if(da.size() < 1)
209 os << "{ }";
210 else
211 {
212 size_t size = da.size() - 1;
213 os << "{ ";
214
215 for(size_t i = 0; i < size; ++i)
216 os << da[i] << ", ";
217
218 os << da[size] << " }";
219 }
220
221 return os;
222 }
223};
224
226{
227 dynamic_array<int> a{10};
228
229 for(size_t i = 0; i < a.size(); ++i)
230 a[i] = (int)i;
231
232 stream << "a = " << a << endl;
233}
234
236{
237 size_t count = 2;
238
239 std::vector< dynamic_array<int> > jagged_array(count); // don't do this
240
241 stream << "At this point, default constructor of dynamic_array is called "
242 << count << " times.\n"<< endl;
243
244 for(size_t i = 0; i < jagged_array.size(); ++i)
245 jagged_array[i] = dynamic_array<int>{ i + 1 };
246
247 stream << "In the for loop, default constructor of dynamic_array is called "
248 << count << " times, and move constructor is called " << count << " times\n" << endl;
249
250 stream << "So, destructor is called total: " << (count + count) << " times " << endl;
251}
252
254{
255 stream << "\nthis is better, but not perfect!!\n" << endl;
256
257 size_t count = 2;
258
259 std::vector< dynamic_array<int> > jagged_array;
260 jagged_array.reserve(count);
261
262 for(size_t i = 0; i < jagged_array.capacity(); ++i)
263 jagged_array.emplace_back(dynamic_array<int>{ i + 1 });
264}
265
266// we never created temporary dynamic array in this function
268{
269 stream << "\nthis is PEREFECT WAY, YOU SHOULD ALWAYS USE THIS METHOD!!\n" << endl;
270
271 size_t count = 10;
272
273 std::vector< dynamic_array<int> > jagged_array;
274 jagged_array.reserve(count);
275
276 for(size_t i = 0; i < jagged_array.capacity(); ++i)
277 {
278 jagged_array.emplace_back(i + 1);
279 // i + 1 is argument for dynamic_array.
280
281 // now std::vector creates dynamic_array
282 // internally, so, no move... only count times of default
283 // constructor of dynamic_array is called.
284
285 for(size_t j = 0; j < jagged_array.back().size(); ++j)
286 jagged_array.back()[j] = (int)j;
287 }
288
289 // note that the constructor of dynamic_array{size_t}
290
291 for(auto& da: jagged_array)
292 {
293 stream << da << endl;
294 }
295}
296
297int main()
298{
299 // examples_for_dynamic_array();
300 // do_not_do_this();
301
302 // is_still_is_not_perfect();
303
305}
void examples_for_dynamic_array()
tpf::sstream stream
Definition: 021-emplace.cpp:4
void do_not_do_this()
auto endl
Definition: 021-emplace.cpp:5
void please_use_this_method()
void is_still_is_not_perfect()
int main()
std::atomic< int > count
Definition: 022-mutex.cpp:10
ElementType * operator&()
Definition: 021-emplace.cpp:97
dynamic_array(dynamic_array &&right_hand_side) noexcept
ElementType & operator[](size_t index)
Definition: 021-emplace.cpp:99
dynamic_array(const dynamic_array &right_hand_side)
Definition: 021-emplace.cpp:77
const ElementType & at(size_t index) const
void resize(size_t count)
Definition: 021-emplace.cpp:33
dynamic_array & operator=(dynamic_array &&right_hand_side) noexcept
ElementType & at(size_t index)
const ElementType & operator[](size_t index) const
friend std::ostream & operator<<(std::ostream &os, const dynamic_array &da)
dynamic_array(size_t size=1)
Definition: 021-emplace.cpp:59
size_t size() const
Definition: 021-emplace.cpp:31
dynamic_array & operator=(const dynamic_array &right_hand_side)
constexpr auto endl
Definition: tpf_output.hpp:973
Stream output operators << are implemented.
#define Tpf_ThrowDebugException(debug_message)
Throw a debug_exception with message as argument.
Definition: tpf_types.hpp:1416