PcapPlusPlus  Next
PointerVector.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <cstddef>
4 #include <cstdio>
5 #include <cstdint>
6 #include <stdexcept>
7 #include <vector>
8 #include <memory>
9 #include <type_traits>
10 
11 #include "DeprecationUtils.h"
12 
14 
17 namespace pcpp
18 {
19  namespace internal
20  {
24  template <class T, class Enable = void> struct Copier
25  {
26  std::unique_ptr<T> operator()(const T& obj) const
27  {
28  return std::unique_ptr<T>(new T(obj));
29  }
30  };
31 
34  template <class T> struct Copier<T, typename std::enable_if<std::is_polymorphic<T>::value>::type>
35  {
36  std::unique_ptr<T> operator()(const T& obj) const
37  {
38  // Clone can return unique_ptr or raw pointer.
39  return std::unique_ptr<T>(std::move(obj.clone()));
40  }
41  };
42  } // namespace internal
43 
49  template <typename T, typename Deleter = std::default_delete<T>> class PointerVector
50  {
51  public:
53  using VectorIterator = typename std::vector<T*>::iterator;
54 
56  using ConstVectorIterator = typename std::vector<T*>::const_iterator;
57 
59  PointerVector() = default;
60 
66  PointerVector(const PointerVector& other) : m_Vector(deepCopyUnsafe(other.m_Vector))
67  {}
68 
71  PointerVector(PointerVector&& other) noexcept : m_Vector(std::move(other.m_Vector))
72  {
73  other.m_Vector.clear();
74  }
75 
78  {
79  freeVectorUnsafe(m_Vector);
80  }
81 
87  {
88  // Self-assignment check.
89  if (this == &other)
90  {
91  return *this;
92  }
93 
94  // Saves a copy of the old pointer to defer cleanup.
95  auto oldValues = m_Vector;
96  try
97  {
98  m_Vector = deepCopyUnsafe(other.m_Vector);
99  }
100  // If an exception is thrown during the copy operation, restore old values and rethrow.
101  catch (const std::exception&)
102  {
103  m_Vector = std::move(oldValues);
104  throw;
105  }
106  // Free old values as the new ones have been successfully assigned.
107  freeVectorUnsafe(oldValues);
108  return *this;
109  }
110 
116  {
117  if (this == &other)
118  {
119  return *this;
120  }
121 
122  // Releases all current elements.
123  clear();
124  // Moves the elements of the other vector.
125  m_Vector = std::move(other.m_Vector);
126  // Explicitly clear the other vector as the standard only guarantees an unspecified valid state after move.
127  other.m_Vector.clear();
128  return *this;
129  }
130 
132  void clear()
133  {
134  freeVectorUnsafe(m_Vector);
135  m_Vector.clear();
136  }
137 
139  void pushBack(std::nullptr_t element, bool freeElementOnError = true) = delete;
140 
146  void pushBack(T* element, bool freeElementOnError = true)
147  {
148  if (element == nullptr)
149  {
150  throw std::invalid_argument("Element is nullptr");
151  }
152 
153  try
154  {
155  m_Vector.push_back(element);
156  }
157  catch (const std::exception&)
158  {
159  if (freeElementOnError)
160  {
161  Deleter{}(element);
162  }
163  throw;
164  }
165  }
166 
171  void pushBack(std::unique_ptr<T> element)
172  {
173  if (!element)
174  {
175  throw std::invalid_argument("Element is nullptr");
176  }
177 
178  // Release is called after the raw pointer is already inserted into the vector to prevent
179  // a memory leak if push_back throws.
180  // cppcheck-suppress danglingLifetime
181  m_Vector.push_back(element.get());
182  element.release();
183  }
184 
188  {
189  return m_Vector.begin();
190  }
191 
195  {
196  return m_Vector.begin();
197  }
198 
202  {
203  return m_Vector.end();
204  }
205 
209  {
210  return m_Vector.end();
211  }
212 
215  size_t size() const
216  {
217  return m_Vector.size();
218  }
219 
221  T* front()
222  {
223  return m_Vector.front();
224  }
225 
227  T const* front() const
228  {
229  return m_Vector.front();
230  }
231 
233  T* back()
234  {
235  return m_Vector.back();
236  }
237 
239  T const* back() const
240  {
241  return m_Vector.back();
242  }
243 
249  {
250  Deleter{}(*position);
251  return m_Vector.erase(position);
252  }
253 
260  PCPP_DEPRECATED("Please use the memory safe 'getAndDetach' instead.")
262  {
263  T* result = *position;
264  position = m_Vector.erase(position);
265  return result;
266  }
267 
271  std::unique_ptr<T> getAndDetach(size_t index)
272  {
273  return getAndDetach(m_Vector.begin() + index);
274  }
275 
280  std::unique_ptr<T> getAndDetach(VectorIterator& position)
281  {
282  std::unique_ptr<T> result(*position);
283  position = m_Vector.erase(position);
284  return result;
285  }
286 
290  std::unique_ptr<T> getAndDetach(const VectorIterator& position)
291  {
292  std::unique_ptr<T> result(*position);
293  m_Vector.erase(position);
294  return result;
295  }
296 
300  T* at(int index)
301  {
302  return m_Vector.at(index);
303  }
304 
308  const T* at(int index) const
309  {
310  return m_Vector.at(index);
311  }
312 
313  private:
317  static std::vector<T*> deepCopyUnsafe(const std::vector<T*>& origin)
318  {
319  std::vector<T*> copyVec;
320  // Allocate the vector initially to ensure no exceptions are thrown during push_back.
321  copyVec.reserve(origin.size());
322 
323  try
324  {
325  for (const auto iter : origin)
326  {
327  std::unique_ptr<T> objCopy = internal::Copier<T>()(*iter);
328  // There shouldn't be a memory leak as the vector is reserved.
329  copyVec.push_back(objCopy.release());
330  }
331  }
332  catch (const std::exception&)
333  {
334  freeVectorUnsafe(copyVec);
335  throw;
336  }
337 
338  return copyVec;
339  }
340 
345  static void freeVectorUnsafe(const std::vector<T*>& origin)
346  {
347  for (auto& obj : origin)
348  {
349  Deleter{}(obj);
350  }
351  }
352 
353  std::vector<T*> m_Vector;
354  };
355 
356 } // namespace pcpp
Definition: PointerVector.h:50
std::unique_ptr< T > getAndDetach(const VectorIterator &position)
Definition: PointerVector.h:290
T * back()
Definition: PointerVector.h:233
void pushBack(std::nullptr_t element, bool freeElementOnError=true)=delete
Adding a nullptr to the vector is not allowed.
void clear()
Clears all elements of the vector while freeing them.
Definition: PointerVector.h:132
VectorIterator erase(VectorIterator position)
Definition: PointerVector.h:248
T * front()
Definition: PointerVector.h:221
ConstVectorIterator end() const
Definition: PointerVector.h:208
ConstVectorIterator begin() const
Definition: PointerVector.h:194
T const * back() const
Definition: PointerVector.h:239
const T * at(int index) const
Definition: PointerVector.h:308
T const * front() const
Definition: PointerVector.h:227
typename std::vector< T * >::iterator VectorIterator
Iterator object that is used for iterating all elements in the vector.
Definition: PointerVector.h:53
PointerVector()=default
A constructor that create an empty instance of this object.
PointerVector & operator=(const PointerVector &other)
Definition: PointerVector.h:86
std::unique_ptr< T > getAndDetach(VectorIterator &position)
Definition: PointerVector.h:280
size_t size() const
Definition: PointerVector.h:215
PointerVector(PointerVector &&other) noexcept
Definition: PointerVector.h:71
T * at(int index)
Definition: PointerVector.h:300
void pushBack(std::unique_ptr< T > element)
Definition: PointerVector.h:171
PointerVector & operator=(PointerVector &&other) noexcept
Definition: PointerVector.h:115
~PointerVector()
A destructor for this class. The destructor frees all elements that are binded to the vector.
Definition: PointerVector.h:77
VectorIterator begin()
Definition: PointerVector.h:187
typename std::vector< T * >::const_iterator ConstVectorIterator
Const iterator object that is used for iterating all elements in a constant vector.
Definition: PointerVector.h:56
PointerVector(const PointerVector &other)
Definition: PointerVector.h:66
std::unique_ptr< T > getAndDetach(size_t index)
Definition: PointerVector.h:271
VectorIterator end()
Definition: PointerVector.h:201
T * getAndRemoveFromVector(VectorIterator &position)
Definition: PointerVector.h:261
void pushBack(T *element, bool freeElementOnError=true)
Definition: PointerVector.h:146
The main namespace for the PcapPlusPlus lib.
A helper struct to facilitate the creation of a copy of an object.
Definition: PointerVector.h:25