Skip to content

Commit e097164

Browse files
YuhongZhang98MongoDB Bot
authored andcommitted
SERVER-100292 Support initializing tracking::unique_ptr with nullptr (#31957)
GitOrigin-RevId: 54a9a52
1 parent daf0409 commit e097164

File tree

2 files changed

+115
-15
lines changed

2 files changed

+115
-15
lines changed

src/mongo/util/tracking/memory.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
#include <boost/smart_ptr/allocate_unique.hpp>
3333
#include <memory>
34-
#include <scoped_allocator>
3534

3635
#include "mongo/util/tracking/allocator.h"
3736
#include "mongo/util/tracking/context.h"
@@ -55,6 +54,8 @@ class unique_ptr {
5554
unique_ptr(Context& Context, Args&&... args)
5655
: _uniquePtr(
5756
boost::allocate_unique<T>(Context.makeAllocator<T>(), std::forward<Args>(args)...)) {}
57+
unique_ptr(Context& Context, std::nullptr_t)
58+
: _uniquePtr(nullptr, boost::alloc_deleter<T, Allocator<T>>(Context.makeAllocator<T>())) {}
5859
unique_ptr(unique_ptr& utp) noexcept : _uniquePtr(*utp.get()){};
5960
unique_ptr(unique_ptr&&) = default;
6061
~unique_ptr() = default;
@@ -84,7 +85,7 @@ class unique_ptr {
8485
}
8586

8687
T* release() noexcept {
87-
return _uniquePtr.release();
88+
return _uniquePtr.release().ptr();
8889
}
8990

9091
void reset(T* ptr = nullptr) noexcept {
@@ -103,7 +104,7 @@ class unique_ptr {
103104
}
104105

105106
unique_ptr<T>& operator=(unique_ptr<T>&& other) noexcept {
106-
_uniquePtr = other._uniquePtr;
107+
_uniquePtr = std::move(other._uniquePtr);
107108
return *this;
108109
}
109110

src/mongo/util/tracking/tracking_allocator_test.cpp

Lines changed: 111 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,6 @@
2828
*/
2929

3030
#include <map>
31-
#include <scoped_allocator>
3231
#include <vector>
3332

3433
#include "mongo/base/string_data.h"
@@ -40,7 +39,18 @@
4039

4140
namespace mongo::tracking {
4241

43-
class AllocatorTest : public unittest::Test {};
42+
class AllocatorTest : public unittest::Test {
43+
protected:
44+
class MockClass {
45+
private:
46+
int64_t u;
47+
int64_t v;
48+
int64_t w;
49+
int64_t x;
50+
int64_t y;
51+
int64_t z;
52+
};
53+
};
4454

4555
TEST_F(AllocatorTest, STLContainerSimple) {
4656
#if _ITERATOR_DEBUG_LEVEL >= 2
@@ -186,16 +196,6 @@ TEST_F(AllocatorTest, STLContainerNested) {
186196
}
187197

188198
TEST_F(AllocatorTest, ManagedObject) {
189-
class MockClass {
190-
private:
191-
int64_t u;
192-
int64_t v;
193-
int64_t w;
194-
int64_t x;
195-
int64_t y;
196-
int64_t z;
197-
};
198-
199199
Context Context;
200200
ASSERT_EQ(0, Context.allocated());
201201

@@ -214,4 +214,103 @@ TEST_F(AllocatorTest, ManagedObject) {
214214
ASSERT_EQ(0, Context.allocated());
215215
}
216216

217+
TEST_F(AllocatorTest, TrackOwnedObjectNull) {
218+
Context Context;
219+
ASSERT_EQ(0, Context.allocated());
220+
221+
{
222+
unique_ptr<MockClass> mockClass = tracking::unique_ptr<MockClass>(Context, nullptr);
223+
ASSERT_EQ(0, Context.allocated());
224+
}
225+
226+
ASSERT_EQ(0, Context.allocated());
227+
}
228+
229+
TEST_F(AllocatorTest, TrackOwnedObjectMoveConstruction) {
230+
Context Context;
231+
ASSERT_EQ(0, Context.allocated());
232+
233+
{
234+
unique_ptr<MockClass> mockClass1 = tracking::make_unique<MockClass>(Context);
235+
auto allocatedMemory = Context.allocated();
236+
ASSERT_GTE(allocatedMemory, sizeof(MockClass));
237+
238+
// Allocation doesn't increase by moving.
239+
unique_ptr<MockClass> mockClass2(std::move(mockClass1));
240+
ASSERT_EQ(Context.allocated(), allocatedMemory);
241+
}
242+
243+
ASSERT_EQ(0, Context.allocated());
244+
}
245+
246+
TEST_F(AllocatorTest, TrackOwnedObjectMoveAssignment) {
247+
Context Context1;
248+
Context Context2;
249+
Context Context3;
250+
ASSERT_EQ(0, Context1.allocated());
251+
ASSERT_EQ(0, Context2.allocated());
252+
ASSERT_EQ(0, Context3.allocated());
253+
254+
{
255+
unique_ptr<MockClass> mockClass1 = tracking::make_unique<MockClass>(Context1);
256+
unique_ptr<MockClass> mockClass2 = tracking::make_unique<MockClass>(Context2);
257+
ASSERT_GTE(Context1.allocated(), sizeof(MockClass));
258+
auto allocatedMemory2 = Context2.allocated();
259+
ASSERT_GTE(allocatedMemory2, sizeof(MockClass));
260+
261+
// mockClass1 deallocates the original object and takes over mockClass2's allocator.
262+
mockClass1 = std::move(mockClass2);
263+
ASSERT_EQ(0, Context1.allocated());
264+
// Allocation doesn't increase by moving.
265+
ASSERT_EQ(Context2.allocated(), allocatedMemory2);
266+
267+
// mockClass1 deallocates the object from mockClass2 and takes over mockClass3's allocator.
268+
unique_ptr<MockClass> mockClass3 = tracking::make_unique<MockClass>(Context3);
269+
auto allocatedMemory3 = Context3.allocated();
270+
ASSERT_GTE(allocatedMemory3, sizeof(MockClass));
271+
mockClass1 = std::move(mockClass3);
272+
ASSERT_EQ(0, Context1.allocated());
273+
ASSERT_EQ(0, Context2.allocated());
274+
// Allocation doesn't increase by moving.
275+
ASSERT_EQ(Context3.allocated(), allocatedMemory3);
276+
}
277+
278+
ASSERT_EQ(0, Context1.allocated());
279+
ASSERT_EQ(0, Context2.allocated());
280+
ASSERT_EQ(0, Context3.allocated());
281+
282+
{
283+
unique_ptr<MockClass> mockClass1 = tracking::unique_ptr<MockClass>(Context1, nullptr);
284+
unique_ptr<MockClass> mockClass2 = tracking::make_unique<MockClass>(Context2);
285+
ASSERT_EQ(0, Context1.allocated());
286+
ASSERT_GTE(Context2.allocated(), sizeof(MockClass));
287+
288+
// mockClass1 deallocates the original object and takes over mockClass2's allocator.
289+
mockClass1 = std::move(mockClass2);
290+
ASSERT_EQ(0, Context1.allocated());
291+
ASSERT_GTE(Context2.allocated(), sizeof(MockClass));
292+
}
293+
294+
ASSERT_EQ(0, Context1.allocated());
295+
ASSERT_EQ(0, Context2.allocated());
296+
ASSERT_EQ(0, Context3.allocated());
297+
}
298+
299+
TEST_F(AllocatorTest, TrackOwnedObjectRelease) {
300+
Context Context;
301+
ASSERT_EQ(0, Context.allocated());
302+
303+
{
304+
unique_ptr<MockClass> mockClass = tracking::make_unique<MockClass>(Context);
305+
ASSERT_GTE(Context.allocated(), sizeof(MockClass));
306+
307+
MockClass* rawMockClass = mockClass.release();
308+
ASSERT_GTE(Context.allocated(), sizeof(MockClass));
309+
310+
delete rawMockClass;
311+
}
312+
313+
// The memory is no longer tracked after the pointer is released.
314+
ASSERT_GTE(Context.allocated(), sizeof(MockClass));
315+
}
217316
} // namespace mongo::tracking

0 commit comments

Comments
 (0)