Commit bb9824ee authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook Github Bot

Implement allocate_unique without catch

Summary: [Folly] Implement `allocate_unique` without `catch` to support `-fno-exceptions` case.

Reviewed By: danzimm

Differential Revision: D9384180

fbshipit-source-id: 8550ad21be2e3eaf4e868ab6866b849828b3d0de
parent 34f01a60
...@@ -562,15 +562,25 @@ std::unique_ptr<T, allocator_delete<Alloc>> allocate_unique( ...@@ -562,15 +562,25 @@ std::unique_ptr<T, allocator_delete<Alloc>> allocate_unique(
Alloc const& alloc, Alloc const& alloc,
Args&&... args) { Args&&... args) {
using traits = std::allocator_traits<Alloc>; using traits = std::allocator_traits<Alloc>;
struct DeferCondDeallocate {
bool& cond;
Alloc& copy;
T* p;
~DeferCondDeallocate() {
if (FOLLY_UNLIKELY(!cond)) {
traits::deallocate(copy, p, 1);
}
}
};
auto copy = alloc; auto copy = alloc;
auto const p = traits::allocate(copy, 1); auto const p = traits::allocate(copy, 1);
try { {
bool constructed = false;
DeferCondDeallocate handler{constructed, copy, p};
traits::construct(copy, p, static_cast<Args&&>(args)...); traits::construct(copy, p, static_cast<Args&&>(args)...);
return {p, allocator_delete<Alloc>(std::move(copy))}; constructed = true;
} catch (...) {
traits::deallocate(copy, p, 1);
throw;
} }
return {p, allocator_delete<Alloc>(std::move(copy))};
} }
struct SysBufferDeleter { struct SysBufferDeleter {
......
...@@ -172,6 +172,58 @@ TEST(allocate_sys_buffer, compiles) { ...@@ -172,6 +172,58 @@ TEST(allocate_sys_buffer, compiles) {
// Freed at the end of the scope. // Freed at the end of the scope.
} }
struct CountedAllocatorStats {
size_t deallocates = 0;
};
template <typename T>
class CountedAllocator : public std::allocator<T> {
private:
CountedAllocatorStats* stats_;
public:
explicit CountedAllocator(CountedAllocatorStats& stats) noexcept
: stats_(&stats) {}
void deallocate(T* p, size_t n) {
std::allocator<T>::deallocate(p, n);
++stats_->deallocates;
}
};
TEST(allocate_unique, ctor_failure) {
struct CtorThrows {
explicit CtorThrows(bool cond) {
if (cond) {
throw std::runtime_error("nope");
}
}
};
using Alloc = CountedAllocator<CtorThrows>;
using Deleter = allocator_delete<CountedAllocator<CtorThrows>>;
{
CountedAllocatorStats stats;
Alloc const alloc(stats);
EXPECT_EQ(0, stats.deallocates);
std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
ptr = allocate_unique<CtorThrows>(alloc, false);
EXPECT_NE(nullptr, ptr);
EXPECT_EQ(0, stats.deallocates);
ptr = nullptr;
EXPECT_EQ(nullptr, ptr);
EXPECT_EQ(1, stats.deallocates);
}
{
CountedAllocatorStats stats;
Alloc const alloc(stats);
EXPECT_EQ(0, stats.deallocates);
std::unique_ptr<CtorThrows, Deleter> ptr{nullptr, Deleter{alloc}};
EXPECT_THROW(
ptr = allocate_unique<CtorThrows>(alloc, true), std::runtime_error);
EXPECT_EQ(nullptr, ptr);
EXPECT_EQ(1, stats.deallocates);
}
}
namespace { namespace {
template <typename T> template <typename T>
struct TestAlloc1 : SysAllocator<T> { struct TestAlloc1 : SysAllocator<T> {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment