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> 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  // Releases all current elements.
118  clear();
119  // Moves the elements of the other vector.
120  m_Vector = std::move(other.m_Vector);
121  // Explicitly clear the other vector as the standard only guarantees an unspecified valid state after move.
122  other.m_Vector.clear();
123  return *this;
124  }
125 
127  void clear()
128  {
129  freeVectorUnsafe(m_Vector);
130  m_Vector.clear();
131  }
132 
134  void pushBack(std::nullptr_t element, bool freeElementOnError = true) = delete;
135 
141  void pushBack(T* element, bool freeElementOnError = true)
142  {
143  if (element == nullptr)
144  {
145  throw std::invalid_argument("Element is nullptr");
146  }
147 
148  try
149  {
150  m_Vector.push_back(element);
151  }
152  catch (const std::exception&)
153  {
154  if (freeElementOnError)
155  {
156  delete element;
157  }
158  throw;
159  }
160  }
161 
166  void pushBack(std::unique_ptr<T> element)
167  {
168  if (!element)
169  {
170  throw std::invalid_argument("Element is nullptr");
171  }
172 
173  // Release is called after the raw pointer is already inserted into the vector to prevent
174  // a memory leak if push_back throws.
175  // cppcheck-suppress danglingLifetime
176  m_Vector.push_back(element.get());
177  element.release();
178  }
179 
183  {
184  return m_Vector.begin();
185  }
186 
190  {
191  return m_Vector.begin();
192  }
193 
197  {
198  return m_Vector.end();
199  }
200 
204  {
205  return m_Vector.end();
206  }
207 
210  size_t size() const
211  {
212  return m_Vector.size();
213  }
214 
216  T* front()
217  {
218  return m_Vector.front();
219  }
220 
222  T const* front() const
223  {
224  return m_Vector.front();
225  }
226 
228  T* back()
229  {
230  return m_Vector.back();
231  }
232 
234  T const* back() const
235  {
236  return m_Vector.back();
237  }
238 
244  {
245  delete (*position);
246  return m_Vector.erase(position);
247  }
248 
255  PCPP_DEPRECATED("Please use the memory safe 'getAndDetach' instead.")
257  {
258  T* result = *position;
259  position = m_Vector.erase(position);
260  return result;
261  }
262 
266  std::unique_ptr<T> getAndDetach(size_t index)
267  {
268  return getAndDetach(m_Vector.begin() + index);
269  }
270 
275  std::unique_ptr<T> getAndDetach(VectorIterator& position)
276  {
277  std::unique_ptr<T> result(*position);
278  position = m_Vector.erase(position);
279  return result;
280  }
281 
285  std::unique_ptr<T> getAndDetach(const VectorIterator& position)
286  {
287  std::unique_ptr<T> result(*position);
288  m_Vector.erase(position);
289  return result;
290  }
291 
295  T* at(int index)
296  {
297  return m_Vector.at(index);
298  }
299 
303  const T* at(int index) const
304  {
305  return m_Vector.at(index);
306  }
307 
308  private:
312  static std::vector<T*> deepCopyUnsafe(const std::vector<T*>& origin)
313  {
314  std::vector<T*> copyVec;
315  // Allocate the vector initially to ensure no exceptions are thrown during push_back.
316  copyVec.reserve(origin.size());
317 
318  try
319  {
320  for (const auto iter : origin)
321  {
322  std::unique_ptr<T> objCopy = internal::Copier<T>()(*iter);
323  // There shouldn't be a memory leak as the vector is reserved.
324  copyVec.push_back(objCopy.release());
325  }
326  }
327  catch (const std::exception&)
328  {
329  for (auto obj : copyVec)
330  {
331  delete obj;
332  }
333  throw;
334  }
335 
336  return copyVec;
337  }
338 
343  static void freeVectorUnsafe(const std::vector<T*>& origin)
344  {
345  for (auto& obj : origin)
346  {
347  delete obj;
348  }
349  }
350 
351  std::vector<T*> m_Vector;
352  };
353 
354 } // namespace pcpp
Definition: PointerVector.h:50
PointerVector()=default
A constructor that create an empty instance of this object.
VectorIterator begin()
Definition: PointerVector.h:182
ConstVectorIterator end() const
Definition: PointerVector.h:203
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
std::unique_ptr< T > getAndDetach(size_t index)
Definition: PointerVector.h:266
T * getAndRemoveFromVector(VectorIterator &position)
Definition: PointerVector.h:256
void pushBack(std::unique_ptr< T > element)
Definition: PointerVector.h:166
VectorIterator erase(VectorIterator position)
Definition: PointerVector.h:243
PointerVector(const PointerVector &other)
Definition: PointerVector.h:66
std::unique_ptr< T > getAndDetach(const VectorIterator &position)
Definition: PointerVector.h:285
PointerVector & operator=(const PointerVector &other)
Definition: PointerVector.h:86
~PointerVector()
A destructor for this class. The destructor frees all elements that are binded to the vector.
Definition: PointerVector.h:77
T const * front() const
Definition: PointerVector.h:222
void pushBack(T *element, bool freeElementOnError=true)
Definition: PointerVector.h:141
T * back()
Definition: PointerVector.h:228
T * at(int index)
Definition: PointerVector.h:295
size_t size() const
Definition: PointerVector.h:210
const T * at(int index) const
Definition: PointerVector.h:303
T * front()
Definition: PointerVector.h:216
PointerVector(PointerVector &&other) noexcept
Definition: PointerVector.h:71
void pushBack(std::nullptr_t element, bool freeElementOnError=true)=delete
Adding a nullptr to the vector is not allowed.
T const * back() const
Definition: PointerVector.h:234
ConstVectorIterator begin() const
Definition: PointerVector.h:189
typename std::vector< T * >::iterator VectorIterator
Iterator object that is used for iterating all elements in the vector.
Definition: PointerVector.h:53
void clear()
Clears all elements of the vector while freeing them.
Definition: PointerVector.h:127
PointerVector & operator=(PointerVector &&other) noexcept
Definition: PointerVector.h:115
std::unique_ptr< T > getAndDetach(VectorIterator &position)
Definition: PointerVector.h:275
VectorIterator end()
Definition: PointerVector.h:196
The main namespace for the PcapPlusPlus lib.
A helper struct to facilitate the creation of a copy of an object.
Definition: PointerVector.h:25