[PATCH] PR libstdc++/70966 make pmr::new_delete_resource() immortal
Jonathan Wakely
jwakely@redhat.com
Wed Jun 20 19:34:00 GMT 2018
Construct the program-wide resource objects using placement new. This
means they have dynamic storage duration and won't be destroyed during
termination.
PR libstdc++/70966
* include/experimental/memory_resource (__resource_adaptor_imp): Add
static assertions to enforce requirements on pointer types.
(__resource_adaptor_imp::get_allocator()): Add noexcept.
(new_delete_resource, null_memory_resource): Return address of an
object with dynamic storage duration.
(__null_memory_resource): Remove.
* testsuite/experimental/memory_resource/70966.cc: New.
Tested x86_64-linux, committed to trunk. I plan to backport this to
the branches too, as it's experimental TS material.
-------------- next part --------------
commit 2a3eba3f0312c8c15f4f2fd7fe7dcc4896036797
Author: Jonathan Wakely <jwakely@redhat.com>
Date: Wed Jun 20 20:01:04 2018 +0100
PR libstdc++/70966 make pmr::new_delete_resource() immortal
Construct the program-wide resource objects using placement new. This
means they have dynamic storage duration and won't be destroyed during
termination.
PR libstdc++/70966
* include/experimental/memory_resource (__resource_adaptor_imp): Add
static assertions to enforce requirements on pointer types.
(__resource_adaptor_imp::get_allocator()): Add noexcept.
(new_delete_resource, null_memory_resource): Return address of an
object with dynamic storage duration.
(__null_memory_resource): Remove.
* testsuite/experimental/memory_resource/70966.cc: New.
diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource
index b8480c2a17b..670a2210804 100644
--- a/libstdc++-v3/include/experimental/memory_resource
+++ b/libstdc++-v3/include/experimental/memory_resource
@@ -33,7 +33,6 @@
#include <new>
#include <atomic>
#include <cstddef>
-#include <bits/alloc_traits.h>
#include <experimental/bits/lfts_config.h>
namespace std {
@@ -258,6 +257,22 @@ namespace pmr {
template <typename _Alloc>
class __resource_adaptor_imp : public memory_resource
{
+ static_assert(is_same<char,
+ typename allocator_traits<_Alloc>::value_type>::value,
+ "Allocator's value_type is char");
+ static_assert(is_same<char*,
+ typename allocator_traits<_Alloc>::pointer>::value,
+ "Allocator's pointer type is value_type*");
+ static_assert(is_same<const char*,
+ typename allocator_traits<_Alloc>::const_pointer>::value,
+ "Allocator's const_pointer type is value_type const*");
+ static_assert(is_same<void*,
+ typename allocator_traits<_Alloc>::void_pointer>::value,
+ "Allocator's void_pointer type is void*");
+ static_assert(is_same<const void*,
+ typename allocator_traits<_Alloc>::const_void_pointer>::value,
+ "Allocator's const_void_pointer type is void const*");
+
public:
using allocator_type = _Alloc;
@@ -276,7 +291,7 @@ namespace pmr {
__resource_adaptor_imp&
operator=(const __resource_adaptor_imp&) = default;
- allocator_type get_allocator() const { return _M_alloc; }
+ allocator_type get_allocator() const noexcept { return _M_alloc; }
protected:
virtual void*
@@ -311,13 +326,13 @@ namespace pmr {
private:
// Calculate Aligned Size
// Returns a size that is larger than or equal to __size and divisible
- // by __alignment, where __alignment is required to be the power of 2.
+ // by __alignment, where __alignment is required to be a power of 2.
static size_t
_S_aligned_size(size_t __size, size_t __alignment)
{ return ((__size - 1)|(__alignment - 1)) + 1; }
// Determine whether alignment meets one of those preconditions:
- // 1. Equals to Zero
+ // 1. Equal to Zero
// 2. Is power of two
static bool
_S_supported (size_t __x)
@@ -337,34 +352,33 @@ namespace pmr {
inline memory_resource*
new_delete_resource() noexcept
{
- static resource_adaptor<std::allocator<char>> __r;
- return static_cast<memory_resource*>(&__r);
+ using type = resource_adaptor<std::allocator<char>>;
+ alignas(type) static unsigned char __buf[sizeof(type)];
+ static type* __r = new(__buf) type;
+ return __r;
}
- template <typename _Alloc>
- class __null_memory_resource : private memory_resource
- {
- protected:
- void*
- do_allocate(size_t, size_t)
- { std::__throw_bad_alloc(); }
-
- void
- do_deallocate(void*, size_t, size_t) noexcept
- { }
-
- bool
- do_is_equal(const memory_resource& __other) const noexcept
- { return this == &__other; }
-
- friend memory_resource* null_memory_resource() noexcept;
- };
-
inline memory_resource*
null_memory_resource() noexcept
{
- static __null_memory_resource<void> __r;
- return static_cast<memory_resource*>(&__r);
+ class type final : public memory_resource
+ {
+ void*
+ do_allocate(size_t, size_t) override
+ { std::__throw_bad_alloc(); }
+
+ void
+ do_deallocate(void*, size_t, size_t) noexcept override
+ { }
+
+ bool
+ do_is_equal(const memory_resource& __other) const noexcept override
+ { return this == &__other; }
+ };
+
+ alignas(type) static unsigned char __buf[sizeof(type)];
+ static type* __r = new(__buf) type;
+ return __r;
}
// The default memory resource
diff --git a/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc b/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc
new file mode 100644
index 00000000000..c0173ffa7a9
--- /dev/null
+++ b/libstdc++-v3/testsuite/experimental/memory_resource/70966.cc
@@ -0,0 +1,56 @@
+// Copyright (C) 2018 Free Software Foundation, Inc.
+//
+// This file is part of the GNU ISO C++ Library. This library is free
+// software; you can redistribute it and/or modify it under the
+// terms of the GNU General Public License as published by the
+// Free Software Foundation; either version 3, or (at your option)
+// any later version.
+
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+
+// You should have received a copy of the GNU General Public License along
+// with this library; see the file COPYING3. If not see
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++14 } }
+
+#include <experimental/memory_resource>
+
+namespace pmr = std::experimental::pmr;
+
+struct X
+{
+ pmr::memory_resource* res = nullptr;
+ void* ptr = nullptr;
+ static constexpr std::size_t n = 64;
+
+ constexpr X() { }
+
+ explicit
+ X(pmr::memory_resource* r) : res(r), ptr(r->allocate(n)) { }
+
+ ~X() { if (ptr) res->deallocate(ptr, n); }
+};
+
+void
+swap(X& lhs, X& rhs) {
+ std::swap(lhs.res, rhs.res);
+ std::swap(lhs.ptr, rhs.ptr);
+}
+
+void
+test01()
+{
+ static X x1;
+ X x2(pmr::new_delete_resource());
+ swap(x1, x2);
+ // Now x1 will deallocate the memory during destruction of static objects.
+}
+
+int main()
+{
+ test01();
+}
More information about the Libstdc++
mailing list