throwing_ptr
Smart pointers that throw on dereference if null
unique_ptr_to_array_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 
9 namespace {
10 
11 struct Foo {
12  static int &object_count() {
13  static int count = 0;
14  return count;
15  }
16  static bool all_objects_deleted() { return object_count() == 0; }
17  Foo() { ++object_count(); }
18  Foo(const Foo &) { ++object_count(); }
19  Foo(Foo &&) {}
20  ~Foo() { --object_count(); }
21 };
22 
23 template <int id> struct Deleter {
24  static int &object_count() {
25  static int count = 0;
26  return count;
27  }
28  static int &deleter_calls() {
29  static int count = 0;
30  return count;
31  }
32  Deleter() { ++object_count(); }
33  Deleter(const Deleter &) { ++object_count(); }
34  Deleter(Deleter &&) {}
35  ~Deleter() { --object_count(); }
36 
37  void operator()(Foo *p) const {
38  ++deleter_calls();
39  delete[] p;
40  }
41 };
42 } // namespace
43 
44 TEST_CASE("unique_ptr to array construction from pointer",
45  "[unique_ptr][array][constructor]") {
46  int *p = new int[10];
47  throwing::unique_ptr<int[]> up(p);
48  REQUIRE(up.get() == p);
49 }
50 
51 TEST_CASE("unique_ptr to array move constructor",
52  "[unique_ptr][array][constructor]") {
53  int *p = new int[10];
54  throwing::unique_ptr<int[]> up(p);
55  throwing::unique_ptr<int[]> up2(std::move(up));
56  REQUIRE(up2.get() == p);
57 }
58 
59 TEST_CASE("unique_ptr to array move constructor from std::unique_ptr",
60  "[unique_ptr][array][constructor]") {
61  int *p = new int[10];
62  std::unique_ptr<int[]> up(p);
63  throwing::unique_ptr<int[]> up2(std::move(up));
64  REQUIRE(up2.get() == p);
65 }
66 
67 TEST_CASE("unique_ptr to array construction from pointer and non reference "
68  "deleter",
69  "[unique_ptr][array][constructor]") {
70  REQUIRE(Foo::object_count() == 0);
71  Deleter<1> d1;
72  REQUIRE(Deleter<1>::object_count() == 1);
73  Deleter<2> d2;
74  REQUIRE(Deleter<2>::object_count() == 1);
75  {
76  std::unique_ptr<Foo[], Deleter<1>> foo1(new Foo[10], d1);
77  REQUIRE(Foo::object_count() == 10);
78 
79  throwing::unique_ptr<Foo[], Deleter<2>> foo2(new Foo[10], d2);
80  REQUIRE(Foo::object_count() == 20);
81  REQUIRE(Deleter<2>::object_count() == Deleter<1>::object_count());
82 
83  REQUIRE(foo2.get() != nullptr);
84  REQUIRE(Deleter<2>::deleter_calls() == 0);
85  }
86  REQUIRE(Foo::object_count() == 0);
87  REQUIRE(Deleter<2>::object_count() == Deleter<1>::object_count());
88  REQUIRE(Deleter<2>::deleter_calls() == 1);
89 }
90 
91 #if !defined(_MSC_VER) || _MSC_VER > 1800
92 TEST_CASE("unique_ptr to array construction from pointer and reference deleter",
93  "[unique_ptr][array][constructor]") {
94  REQUIRE(Foo::object_count() == 0);
95  Deleter<3> d1;
96  REQUIRE(Deleter<3>::object_count() == 1);
97  Deleter<4> d2;
98  REQUIRE(Deleter<4>::object_count() == 1);
99  {
100  std::unique_ptr<Foo[], Deleter<3> &> foo1(new Foo[10], d1);
101  REQUIRE(Foo::object_count() == 10);
102  REQUIRE(Deleter<3>::object_count() == 1);
103 
104  throwing::unique_ptr<Foo[], Deleter<4> &> foo2(new Foo[10], d2);
105  REQUIRE(Foo::object_count() == 20);
106  REQUIRE(Deleter<4>::object_count() == 1);
107 
108  REQUIRE(foo2.get() != nullptr);
109  REQUIRE(Deleter<4>::deleter_calls() == 0);
110  }
111  REQUIRE(Deleter<3>::object_count() == 1);
112  REQUIRE(Deleter<4>::object_count() == 1);
113  REQUIRE(Deleter<4>::deleter_calls() == 1);
114 }
115 #endif
116 
117 TEST_CASE("unique_ptr to array construction from pointer and move reference "
118  "deleter",
119  "[unique_ptr][array][constructor]") {
120  REQUIRE(Foo::object_count() == 0);
121  Deleter<5> d1;
122  REQUIRE(Deleter<5>::object_count() == 1);
123  Deleter<6> d2;
124  REQUIRE(Deleter<6>::object_count() == 1);
125  {
126  std::unique_ptr<Foo[], Deleter<5>> foo1(new Foo[10], std::move(d1));
127  REQUIRE(Foo::object_count() == 10);
128 
129  throwing::unique_ptr<Foo[], Deleter<6>> foo2(new Foo[10],
130  std::move(d2));
131  REQUIRE(Foo::object_count() == 20);
132  REQUIRE(Deleter<5>::object_count() == Deleter<6>::object_count());
133 
134  REQUIRE(foo2.get() != nullptr);
135  REQUIRE(Deleter<6>::deleter_calls() == 0);
136  }
137  REQUIRE(Deleter<6>::object_count() == Deleter<5>::object_count());
138  REQUIRE(Deleter<6>::deleter_calls() == 1);
139 }
140 
141 TEST_CASE("unique_ptr to array construction from convertible pointer and copy "
142  "deleter",
143  "[unique_ptr][array][constructor]") {
144  REQUIRE(Foo::object_count() == 0);
145  Deleter<7> d1;
146  REQUIRE(Deleter<7>::object_count() == 1);
147  Deleter<8> d2;
148  REQUIRE(Deleter<8>::object_count() == 1);
149  {
150  std::unique_ptr<Foo[], Deleter<7>> foo1(new Foo[10], d1);
151  REQUIRE(Foo::object_count() == 10);
152  throwing::unique_ptr<Foo[], Deleter<8>> foo2(new Foo[10], d2);
153  REQUIRE(Foo::object_count() == 20);
154  REQUIRE(Deleter<8>::object_count() == Deleter<7>::object_count());
155 
156  REQUIRE(foo2.get() != nullptr);
157  REQUIRE(Deleter<8>::deleter_calls() == 0);
158  {
159  std::unique_ptr<Foo[], Deleter<7>> moved_foo1(std::move(foo1));
160  REQUIRE(Foo::object_count() == 20);
161  throwing::unique_ptr<Foo[], Deleter<8>> moved_foo2(std::move(foo2));
162  REQUIRE(Foo::object_count() == 20);
163  REQUIRE(Deleter<8>::object_count() == Deleter<7>::object_count());
164  REQUIRE(Deleter<8>::deleter_calls() == 0);
165  REQUIRE(moved_foo2.get() != nullptr);
166  }
167  REQUIRE(Deleter<8>::object_count() == Deleter<7>::object_count());
168  REQUIRE(Deleter<8>::deleter_calls() == 1);
169  }
170  REQUIRE(Deleter<8>::object_count() == Deleter<7>::object_count());
171  REQUIRE(Deleter<8>::deleter_calls() == 1);
172 }
173 
174 #if !defined(_MSC_VER) || _MSC_VER > 1800
175 TEST_CASE("unique_ptr to array construction from convertible pointer and move "
176  "deleter",
177  "[unique_ptr][array][constructor]") {
178  REQUIRE(Foo::object_count() == 0);
179  Deleter<9> d1;
180  REQUIRE(Deleter<9>::object_count() == 1);
181  Deleter<10> d2;
182  REQUIRE(Deleter<10>::object_count() == 1);
183  {
184  std::unique_ptr<Foo[], Deleter<9> &> foo1(new Foo[10], d1);
185  REQUIRE(Foo::object_count() == 10);
186 
187  throwing::unique_ptr<Foo[], Deleter<10> &> foo2(new Foo[10], d2);
188  REQUIRE(Foo::object_count() == 20);
189  REQUIRE(Deleter<10>::object_count() == Deleter<9>::object_count());
190 
191  REQUIRE(foo2.get() != nullptr);
192  REQUIRE(Deleter<10>::deleter_calls() == 0);
193  {
194  std::unique_ptr<Foo[], Deleter<9>> moved_foo1(std::move(foo1));
195  REQUIRE(Foo::object_count() == 20);
196  throwing::unique_ptr<Foo[], Deleter<10>> moved_foo2(
197  std::move(foo2));
198  REQUIRE(Foo::object_count() == 20);
199  REQUIRE(Deleter<10>::object_count() == Deleter<9>::object_count());
200  REQUIRE(Deleter<10>::deleter_calls() == 0);
201  REQUIRE(moved_foo2.get() != nullptr);
202  }
203  REQUIRE(Deleter<10>::object_count() == Deleter<9>::object_count());
204  REQUIRE(Deleter<10>::deleter_calls() == 1);
205  }
206  REQUIRE(Deleter<10>::object_count() == Deleter<9>::object_count());
207  REQUIRE(Deleter<10>::deleter_calls() == 1);
208 }
209 #endif
TEST_CASE("unique_ptr to array reset to convertible", "[unique_ptr][array][reset][conv.qual]")