throwing_ptr
Smart pointers that throw on dereference if null
unique_ptr_construction.cpp
Go to the documentation of this file.
1 // Copyright Claudio Bantaloukas 2017-2018.
2 // Distributed under the Boost Software License, Version 1.0.
3 // (See accompanying file LICENSE or copy at
4 // http://www.boost.org/LICENSE_1_0.txt)
5 
6 #include <catch.hpp>
7 #include <throwing/unique_ptr.hpp>
8 #ifdef _MSC_VER
9 #pragma warning(disable : 4521)
10 #endif
11 
12 namespace {
13 struct Foo {
14  Foo() : m_deleted(nullptr) {}
15  Foo(bool &deleted) : m_deleted(&deleted) {}
16  Foo(const Foo &p) : m_deleted(p.m_deleted) {}
17  Foo(Foo &&p) : m_deleted(p.m_deleted) {}
18  Foo &operator=(const Foo &other) {
19  if (this != &other) {
20  m_deleted = other.m_deleted;
21  }
22  return *this;
23  }
24  ~Foo() { *m_deleted = true; }
25  bool *m_deleted;
26 };
27 
28 struct Deleter {
29  Deleter() : m_copied(nullptr), m_moved(nullptr), m_called(nullptr) {}
30  Deleter(bool *copied, bool *moved, bool *called)
31  : m_copied(copied), m_moved(moved), m_called(called) {}
32  Deleter(const Deleter &d)
33  : m_copied(d.m_copied), m_moved(d.m_moved), m_called(d.m_called) {
34  *m_copied = true;
35  }
36 
37  Deleter(Deleter &d)
38  : m_copied(d.m_copied), m_moved(d.m_moved), m_called(d.m_called) {
39  *m_copied = true;
40  }
41 
42  Deleter(Deleter &&d)
43  : m_copied(std::move(d.m_copied)), m_moved(std::move(d.m_moved)),
44  m_called(std::move(d.m_called)) {
45  *m_moved = true;
46  }
47  Deleter &operator=(const Deleter &other) {
48  if (this != &other) {
49  *m_copied = true;
50  }
51  return *this;
52  }
53 
54  void operator()(Foo *p) const {
55  *m_called = true;
56  delete p;
57  }
58  bool *m_copied;
59  bool *m_moved;
60  bool *m_called;
61 };
62 } // namespace
63 
64 TEST_CASE("unique_ptr to single object constructor from pointer",
65  "[unique_ptr][single][constructor]") {
66  int *p = new int;
67  throwing::unique_ptr<int> up(p);
68  REQUIRE(up.get() == p);
69 }
70 
71 TEST_CASE("unique_ptr to single object move constructor",
72  "[unique_ptr][single][constructor]") {
73  int *p = new int;
74  throwing::unique_ptr<int> up(p);
75  throwing::unique_ptr<int> up2(std::move(up));
76  REQUIRE(up2.get() == p);
77 }
78 
79 TEST_CASE("unique_ptr to single object move constructor from std::unique_ptr",
80  "[unique_ptr][single][constructor]") {
81  int *p = new int;
82  std::unique_ptr<int> up(p);
83  throwing::unique_ptr<int> up2(std::move(up));
84  REQUIRE(up2.get() == p);
85 }
86 
87 TEST_CASE("unique_ptr to single object constructor from pointer and non "
88  "reference deleter",
89  "[unique_ptr][single][constructor]") {
90  bool d1_copied = false;
91  bool d1_moved = false;
92  bool d1_called = false;
93  bool ptr1_deleted = false;
94  bool d2_copied = false;
95  bool d2_moved = false;
96  bool d2_called = false;
97  bool ptr2_deleted = false;
98  Deleter d1(&d1_copied, &d1_moved, &d1_called);
99  Deleter d2(&d2_copied, &d2_moved, &d2_called);
100  {
101  std::unique_ptr<Foo, Deleter> foo1(new Foo(ptr1_deleted), d1);
102  throwing::unique_ptr<Foo, Deleter> foo2(new Foo(ptr2_deleted), d2);
103  REQUIRE(foo2.get() != nullptr);
104  REQUIRE(d2_copied == d1_copied);
105  REQUIRE(d2_moved == d1_moved);
106  REQUIRE(d2_called == d1_called);
107  REQUIRE_FALSE(ptr2_deleted);
108  }
109  REQUIRE(d2_copied == d1_copied);
110  REQUIRE(d2_moved == d1_moved);
111  REQUIRE(d2_called == d1_called);
112  REQUIRE(ptr2_deleted);
113 }
114 
115 #if !defined(_MSC_VER) || _MSC_VER > 1800
116 TEST_CASE("unique_ptr to single object constructor from pointer and reference "
117  "to deleter",
118  "[unique_ptr][single][constructor]") {
119  bool d1_copied = false;
120  bool d1_moved = false;
121  bool d1_called = false;
122  bool ptr1_deleted = false;
123  bool d2_copied = false;
124  bool d2_moved = false;
125  bool d2_called = false;
126  bool ptr2_deleted = false;
127  Deleter d1(&d1_copied, &d1_moved, &d1_called);
128  Deleter d2(&d2_copied, &d2_moved, &d2_called);
129  {
130  std::unique_ptr<Foo, Deleter &> foo1(new Foo(ptr1_deleted), d1);
131  throwing::unique_ptr<Foo, Deleter &> foo2(new Foo(ptr2_deleted), d2);
132  REQUIRE(foo2.get() != nullptr);
133  REQUIRE(d2_copied == d1_copied);
134  REQUIRE(d2_moved == d1_moved);
135  REQUIRE(d2_called == d1_called);
136  REQUIRE_FALSE(ptr2_deleted);
137  }
138  REQUIRE(d2_copied == d1_copied);
139  REQUIRE(d2_moved == d1_moved);
140  REQUIRE(d2_called == d1_called);
141  REQUIRE(ptr2_deleted);
142 }
143 #endif
144 
145 TEST_CASE("unique_ptr to single object constructor from pointer and "
146  "move-reference to deleter",
147  "[unique_ptr][single][constructor]") {
148  bool d1_copied = false;
149  bool d1_moved = false;
150  bool d1_called = false;
151  bool ptr1_deleted = false;
152  bool d2_copied = false;
153  bool d2_moved = false;
154  bool d2_called = false;
155  bool ptr2_deleted = false;
156  Deleter d1(&d1_copied, &d1_moved, &d1_called);
157  Deleter d2(&d2_copied, &d2_moved, &d2_called);
158  {
159  std::unique_ptr<Foo, Deleter> foo1(new Foo(ptr1_deleted),
160  std::move(d1));
161  throwing::unique_ptr<Foo, Deleter> foo2(new Foo(ptr2_deleted),
162  std::move(d2));
163  REQUIRE(foo2.get() != nullptr);
164  REQUIRE(d2_copied == d1_copied);
165  REQUIRE(d2_moved == d1_moved);
166  REQUIRE(d2_called == d1_called);
167  REQUIRE_FALSE(ptr2_deleted);
168  }
169  REQUIRE(d2_copied == d1_copied);
170  REQUIRE(d2_moved == d1_moved);
171  REQUIRE(d2_called == d1_called);
172  REQUIRE(ptr2_deleted);
173 }
174 
175 TEST_CASE("unique_ptr to single object constructor from convertible pointer "
176  "and copied deleter",
177  "[unique_ptr][single][constructor]") {
178  bool d1_copied = false;
179  bool d1_moved = false;
180  bool d1_called = false;
181  bool ptr1_deleted = false;
182  bool d2_copied = false;
183  bool d2_moved = false;
184  bool d2_called = false;
185  bool ptr2_deleted = false;
186  auto clear_all = [&]() {
187  d1_copied = d2_copied = d1_called = d2_called = d1_moved = d2_moved =
188  false;
189  };
190  Deleter d1(&d1_copied, &d1_moved, &d1_called);
191  Deleter d2(&d2_copied, &d2_moved, &d2_called);
192  {
193  std::unique_ptr<Foo, Deleter> sup6a(new Foo(ptr1_deleted), d1);
194  throwing::unique_ptr<Foo, Deleter> tup6a(new Foo(ptr2_deleted), d2);
195  REQUIRE(tup6a.get() != nullptr);
196  REQUIRE(d2_copied == d1_copied);
197  REQUIRE(d2_moved == d1_moved);
198  REQUIRE(d2_called == d1_called);
199  REQUIRE_FALSE(ptr2_deleted);
200  clear_all();
201  {
202  std::unique_ptr<Foo, Deleter> sup6b(std::move(sup6a));
203  REQUIRE(sup6b.get() != nullptr);
204  REQUIRE_FALSE(ptr2_deleted);
205  throwing::unique_ptr<Foo, Deleter> tup6b(std::move(tup6a));
206  REQUIRE(tup6b.get() != nullptr);
207  REQUIRE(d2_copied == d1_copied);
208  REQUIRE(d2_moved == d1_moved);
209  REQUIRE(d2_called == d1_called);
210  REQUIRE_FALSE(ptr2_deleted);
211  clear_all();
212  }
213  REQUIRE(ptr2_deleted);
214  }
215 }
216 
217 #if !defined(_MSC_VER) || _MSC_VER > 1800
218 TEST_CASE("unique_ptr to single object constructor from convertible object and "
219  "moved deleter",
220  "[unique_ptr][single][constructor]") {
221  bool d1_copied = false;
222  bool d1_moved = false;
223  bool d1_called = false;
224  bool ptr1_deleted = false;
225  bool d2_copied = false;
226  bool d2_moved = false;
227  bool d2_called = false;
228  bool ptr2_deleted = false;
229  auto clear_all = [&]() {
230  d1_copied = d2_copied = d1_called = d2_called = d1_moved = d2_moved =
231  false;
232  };
233  Deleter d1(&d1_copied, &d1_moved, &d1_called);
234  Deleter d2(&d2_copied, &d2_moved, &d2_called);
235  {
236  std::unique_ptr<Foo, Deleter &> sup6a(new Foo(ptr1_deleted), d1);
237  throwing::unique_ptr<Foo, Deleter &> tup6a(new Foo(ptr2_deleted), d2);
238  REQUIRE(tup6a.get() != nullptr);
239  REQUIRE(d2_copied == d1_copied);
240  REQUIRE(d2_moved == d1_moved);
241  REQUIRE(d2_called == d1_called);
242  REQUIRE_FALSE(ptr2_deleted);
243  clear_all();
244  {
245  std::unique_ptr<Foo, Deleter> sup6b(std::move(sup6a));
246  REQUIRE(sup6b.get() != nullptr);
247  REQUIRE_FALSE(ptr2_deleted);
248 
249  throwing::unique_ptr<Foo, Deleter> tup6b(std::move(tup6a));
250  REQUIRE(tup6b.get() != nullptr);
251  REQUIRE(d2_copied == d1_copied);
252  REQUIRE(d2_moved == d1_moved);
253  REQUIRE(d2_called == d1_called);
254  REQUIRE_FALSE(ptr2_deleted);
255  clear_all();
256  }
257  REQUIRE(ptr2_deleted);
258  }
259 }
260 #endif
TEST_CASE("unique_ptr to array reset to convertible", "[unique_ptr][array][reset][conv.qual]")