Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Minor cleanup/improvements in unique_ptr_test #1266

Merged
merged 4 commits into from
Sep 1, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 69 additions & 60 deletions test/ctl/unique_ptr_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -24,72 +24,56 @@
// #include <type_traits>
// #define ctl std

template<typename T, typename D = ctl::default_delete<T>>
using Ptr = ctl::unique_ptr<T, D>;
using ctl::unique_ptr;
using ctl::make_unique;
using ctl::make_unique_for_overwrite;

template<typename T, typename... Args>
Ptr<T>
Mk(Args&&... args)
{
return ctl::make_unique<T, Args...>(ctl::forward<Args>(args)...);
}

template<typename T>
Ptr<T>
MkRaw()
{
return ctl::make_unique_for_overwrite<T>();
}

// #undef ctl
#undef ctl

// The following few definitions are used to get observability into aspects of
// an object's lifecycle, to make sure that e.g. constructing a unique_ptr of a
// type does not construct an object, and that make_unique does construct an
// object.
static int g = 0;

struct SetsGDeleter
struct ConstructG
{
void operator()(auto* x) const noexcept
ConstructG()
{
++g;
delete x;
}
};

struct StatefulDeleter
struct DestructG
{
char state;
void operator()(auto* x) const noexcept
~DestructG()
{
++g;
}
};

struct FinalDeleter final
struct CallG
{
void operator()(auto* x) const noexcept
{
++g;
}
};

static_assert(sizeof(Ptr<int, SetsGDeleter>) == sizeof(int*));

// not everyone uses [[no_unique_address]]...
static_assert(!ctl::is_same_v<Ptr<int>, ctl::unique_ptr<int>> ||
sizeof(Ptr<int, FinalDeleter>) == sizeof(int*));
// A unique_ptr with an empty deleter should be the same size as a raw pointer.
static_assert(sizeof(unique_ptr<int, decltype([] {})>) == sizeof(int*));

struct SetsGCtor
struct FinalDeleter final
{
SetsGCtor()
void operator()(auto* x) const noexcept
{
++g;
}
};

struct SetsGDtor
{
~SetsGDtor()
{
++g;
}
};
// ctl::unique_ptr does not need to inherit from its deleter for this property;
// the STL often does, though, so we don't hold them to the following.
static_assert(!ctl::is_same_v<unique_ptr<int>, ctl::unique_ptr<int>> ||
sizeof(unique_ptr<int, FinalDeleter>) == sizeof(int*));

struct Base
{};
Expand All @@ -100,36 +84,62 @@ struct Derived : Base
int
main()
{
int a;

{
Ptr<int> x(new int(5));
// Shouldn't cause any memory leaks.
unique_ptr<int> x(new int(5));
}

{
Ptr<int, SetsGDeleter> x(new int());
// Deleter is called if the pointer is non-null when reset.
unique_ptr<int, CallG> x(&a);
x.reset();
if (g != 1)
return 1;
}

{
g = 0;
Ptr<int, SetsGDeleter> x(new int());
delete x.release();
// Deleter is not called if the pointer is null when reset.
unique_ptr<int, CallG> x(&a);
x.release();
x.reset();
if (g)
return 17;
}

{
Ptr<int> x(new int(5)), y(new int(6));
g = 0;
// Deleter is called when the pointer goes out of scope.
{
unique_ptr<int, CallG> x(&a);
}
if (!g)
return 18;
}

{
g = 0;
// Deleter is called if scope ends exceptionally.
try {
unique_ptr<int, CallG> x(&a);
throw 'a';
} catch (char) {
}
if (!g)
return 19;
}

{
unique_ptr<int> x(new int(5)), y(new int(6));
x.swap(y);
if (*x != 6 || *y != 5)
return 2;
}

{
Ptr<int> x;
unique_ptr<int> x;
if (x)
return 3;
x.reset(new int(5));
Expand All @@ -139,17 +149,17 @@ main()

{
g = 0;
Ptr<SetsGCtor> x;
unique_ptr<ConstructG> x;
if (g)
return 5;
x = Mk<SetsGCtor>();
x = make_unique<ConstructG>();
if (g != 1)
return 6;
}

{
g = 0;
auto x = Mk<SetsGDtor>();
auto x = make_unique<DestructG>();
if (g)
return 7;
x.reset();
Expand All @@ -161,9 +171,9 @@ main()

{
g = 0;
Ptr<SetsGDtor> x, y;
x = Mk<SetsGDtor>();
y = Mk<SetsGDtor>();
unique_ptr<DestructG> x, y;
x = make_unique<DestructG>();
y = make_unique<DestructG>();
#if 0
// shouldn't compile
x = y;
Expand All @@ -178,7 +188,7 @@ main()
{
g = 0;
{
auto x = Mk<SetsGDtor>();
auto x = make_unique<DestructG>();
}
if (g != 1)
return 12;
Expand All @@ -187,7 +197,7 @@ main()
{
g = 0;
{
auto x = Mk<SetsGDtor>();
auto x = make_unique<DestructG>();
delete x.release();
}
if (g != 1)
Expand All @@ -199,13 +209,13 @@ main()
// side effects it has are illegal to detect?
{
g = 0;
auto x = MkRaw<DefaultInitialized>();
auto x = make_unique_for_overwrite<DefaultInitialized>();
if (g)
return 14;
x.reset();
if (g)
return 15;
x = Mk<DefaultInitialized>();
x = make_unique<DefaultInitialized>();
if (g != 1)
return 16;
}
Expand All @@ -214,16 +224,15 @@ main()
{
int a;
// Should compile.
Ptr<int, FinalDeleter> x(&a);
Ptr<int, StatefulDeleter> y(&a);
unique_ptr<int, FinalDeleter> x(&a);
}

{
Ptr<Base> x(new Base);
unique_ptr<Base> x(new Base);
x.reset(new Derived);

Ptr<Derived> y(new Derived);
Ptr<Base> z(ctl::move(y));
unique_ptr<Derived> y(new Derived);
unique_ptr<Base> z(ctl::move(y));
}

CheckForMemoryLeaks();
Expand Down
Loading