mirror of
https://github.com/boostorg/core.git
synced 2025-05-09 23:03:54 +00:00
Move construct and destroy from Smart_Ptr to Core
This commit is contained in:
parent
f3a382c017
commit
612069c7e4
125
doc/alloc_construct.qbk
Normal file
125
doc/alloc_construct.qbk
Normal file
@ -0,0 +1,125 @@
|
||||
[/
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
]
|
||||
|
||||
[section:alloc_construct alloc_construct]
|
||||
|
||||
[simplesect Authors]
|
||||
|
||||
* Glen Fernandes
|
||||
|
||||
[endsimplesect]
|
||||
|
||||
[section Overview]
|
||||
|
||||
The header <boost/core/alloc_construct.hpp> provides function templates
|
||||
`alloc_construct`, `alloc_construct_n`, `alloc_destroy`, and `alloc_destroy_n`
|
||||
for allocator aware and exception safe construction and destruction of objects
|
||||
and arrays.
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Example]
|
||||
|
||||
The following example allocates storage for an array of `n` elements of `T`
|
||||
using an allocator `a` and constructs `T` elements in that storage. If any
|
||||
exception was thrown during construction of an element, the constructed
|
||||
elements are destroyed in reverse order.
|
||||
|
||||
```
|
||||
template<class A>
|
||||
auto create(A& a, std::size_t n)
|
||||
{
|
||||
auto p = a.allocate(n);
|
||||
try {
|
||||
boost::alloc_construct_n(a, boost::to_address(p), n);
|
||||
} catch (...) {
|
||||
a.deallocate(n);
|
||||
throw;
|
||||
}
|
||||
return p;
|
||||
}
|
||||
```
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Reference]
|
||||
|
||||
```
|
||||
namespace boost {
|
||||
|
||||
template<class A, class T>
|
||||
void alloc_destroy(A& a, T* p);
|
||||
|
||||
template<class A, class T>
|
||||
void alloc_destroy_n(A& a, T* p, std::size_t n);
|
||||
|
||||
template<class A, class T, class U>
|
||||
void alloc_construct(A& a, T* p, U&&... u);
|
||||
|
||||
template<class A, class T>
|
||||
void alloc_construct_n(A& a, T* p, std::size_t n);
|
||||
|
||||
template<class A, class T>
|
||||
void alloc_construct_n(A& a, T* p, std::size_t n, const T* l, std::size_t m);
|
||||
|
||||
} /* boost */
|
||||
```
|
||||
|
||||
[section Functions]
|
||||
|
||||
[variablelist
|
||||
[[`template<class A, class T> void alloc_destroy(A& a, T* p);`]
|
||||
[[variablelist
|
||||
[[Requires][`A` is an _Allocator_]]
|
||||
[[Effects][`std::allocator_traits<A>::destroy(a, p)`.]]]]]
|
||||
[[`template<class A, class T> void alloc_destroy_n(A& a, T* p,
|
||||
std::size_t n);`]
|
||||
[[variablelist
|
||||
[[Requires][`A` is an _Allocator_]]
|
||||
[[Effects]
|
||||
[Destroys each element in reverse order by calling
|
||||
`std::allocator_traits<A>::destroy(a, &p[i])`.]]]]]
|
||||
[[`template<class A, class T, class U> void alloc_construct(A& a, T* p,
|
||||
U&&... u);`]
|
||||
[[variablelist
|
||||
[[Requires][`A` is an _Allocator_]]
|
||||
[[Effects]
|
||||
[`std::allocator_traits<A>::construct(a, p, std::forward<U>(u)...)`.]]]]]
|
||||
[[`template<class A, class T> void alloc_construct_n(A& a, T* p,
|
||||
std::size_t n);`]
|
||||
[[variablelist
|
||||
[[Requires][`A` is an _Allocator_]]
|
||||
[[Effects]
|
||||
[Constructs each element in order by calling
|
||||
`std::allocator_traits<A>::construct(a, &p[i])`.]]
|
||||
[[Remarks]
|
||||
[If an exception is thrown, destroys each element in reverse order by
|
||||
calling `std::allocator_traits<A>::destroy(a, &p[i])`.]]]]]
|
||||
[[`template<class A, class T> void alloc_construct_n(A& a, T* p, std::size_t n,
|
||||
const T* l, std::size_t m);`]
|
||||
[[variablelist
|
||||
[[Requires][`A` is an _Allocator_]]
|
||||
[[Effects]
|
||||
[Constructs each element in order by calling
|
||||
`std::allocator_traits<A>::construct(a, &p[i], l[i % m])`.]]
|
||||
[[Remarks]
|
||||
[If an exception is thrown, destroys each element in reverse order by
|
||||
calling `std::allocator_traits<A>::destroy(a, &p[i])`.]]]]]]
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Acknowledgments]
|
||||
|
||||
Glen Fernandes originally implemented this functionality in Boost.Smart_ptr and
|
||||
later moved these functions to Boost.Core for use in multiple Boost libraries.
|
||||
|
||||
[endsect]
|
||||
|
||||
[endsect]
|
@ -39,6 +39,7 @@ criteria for inclusion is that the utility component be:
|
||||
[endsect]
|
||||
|
||||
[include addressof.qbk]
|
||||
[include alloc_construct.qbk]
|
||||
[include checked_delete.qbk]
|
||||
[include default_allocator.qbk]
|
||||
[include demangle.qbk]
|
||||
|
209
include/boost/core/alloc_construct.hpp
Normal file
209
include/boost/core/alloc_construct.hpp
Normal file
@ -0,0 +1,209 @@
|
||||
/*
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#ifndef BOOST_CORE_ALLOC_CONSTRUCT_HPP
|
||||
#define BOOST_CORE_ALLOC_CONSTRUCT_HPP
|
||||
|
||||
#include <boost/core/noinit_adaptor.hpp>
|
||||
|
||||
namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_destroy(A& a, T* p)
|
||||
{
|
||||
std::allocator_traits<A>::destroy(a, p);
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_destroy_n(A& a, T* p, std::size_t n)
|
||||
{
|
||||
while (n > 0) {
|
||||
std::allocator_traits<A>::destroy(a, p + --n);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_destroy(A&, T* p)
|
||||
{
|
||||
p->~T();
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_destroy_n(A&, T* p, std::size_t n)
|
||||
{
|
||||
while (n > 0) {
|
||||
p[--n].~T();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
|
||||
template<class A, class T>
|
||||
class alloc_destroyer {
|
||||
public:
|
||||
alloc_destroyer(A& a, T* p) BOOST_NOEXCEPT
|
||||
: a_(a),
|
||||
p_(p),
|
||||
n_(0) { }
|
||||
|
||||
~alloc_destroyer() {
|
||||
boost::alloc_destroy_n(a_, p_, n_);
|
||||
}
|
||||
|
||||
std::size_t& size() BOOST_NOEXCEPT {
|
||||
return n_;
|
||||
}
|
||||
|
||||
private:
|
||||
alloc_destroyer(const alloc_destroyer&);
|
||||
alloc_destroyer& operator=(const alloc_destroyer&);
|
||||
|
||||
A& a_;
|
||||
T* p_;
|
||||
std::size_t n_;
|
||||
};
|
||||
|
||||
} /* detail */
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct(A& a, T* p)
|
||||
{
|
||||
std::allocator_traits<A>::construct(a, p);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template<class A, class T, class U, class... V>
|
||||
inline void
|
||||
alloc_construct(A& a, T* p, U&& u, V&&... v)
|
||||
{
|
||||
std::allocator_traits<A>::construct(a, p, std::forward<U>(u),
|
||||
std::forward<V>(v)...);
|
||||
}
|
||||
#else
|
||||
template<class A, class T, class U>
|
||||
inline void
|
||||
alloc_construct(A& a, T* p, U&& u)
|
||||
{
|
||||
std::allocator_traits<A>::construct(a, p, std::forward<U>(u));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
template<class A, class T, class U>
|
||||
inline void
|
||||
alloc_construct(A& a, T* p, const U& u)
|
||||
{
|
||||
std::allocator_traits<A>::construct(a, p, u);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct_n(A& a, T* p, std::size_t n)
|
||||
{
|
||||
detail::alloc_destroyer<A, T> hold(a, p);
|
||||
for (std::size_t& i = hold.size(); i < n; ++i) {
|
||||
std::allocator_traits<A>::construct(a, p + i);
|
||||
}
|
||||
hold.size() = 0;
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct_n(A& a, T* p, std::size_t n, const T* l, std::size_t m)
|
||||
{
|
||||
detail::alloc_destroyer<A, T> hold(a, p);
|
||||
for (std::size_t& i = hold.size(); i < n; ++i) {
|
||||
std::allocator_traits<A>::construct(a, p + i, l[i % m]);
|
||||
}
|
||||
hold.size() = 0;
|
||||
}
|
||||
#else
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct(A&, T* p)
|
||||
{
|
||||
::new(static_cast<void*>(p)) T();
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct(noinit_adaptor<A>&, T* p)
|
||||
{
|
||||
::new(static_cast<void*>(p)) T;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
template<class A, class T, class U, class... V>
|
||||
inline void
|
||||
alloc_construct(A&, T* p, U&& u, V&&... v)
|
||||
{
|
||||
::new(static_cast<void*>(p)) T(std::forward<U>(u), std::forward<V>(v)...);
|
||||
}
|
||||
#else
|
||||
template<class A, class T, class U>
|
||||
inline void
|
||||
alloc_construct(A& a, T* p, U&& u)
|
||||
{
|
||||
::new(static_cast<void*>(p)) T(std::forward<U>(u));
|
||||
}
|
||||
#endif
|
||||
#else
|
||||
template<class A, class T, class U>
|
||||
inline void
|
||||
alloc_construct(A&, T* p, const U& u)
|
||||
{
|
||||
::new(static_cast<void*>(p)) T(u);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct_n(A& a, T* p, std::size_t n)
|
||||
{
|
||||
detail::alloc_destroyer<A, T> hold(a, p);
|
||||
for (std::size_t& i = hold.size(); i < n; ++i) {
|
||||
::new(static_cast<void*>(p + i)) T();
|
||||
}
|
||||
hold.size() = 0;
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct_n(noinit_adaptor<A>& a, T* p, std::size_t n)
|
||||
{
|
||||
detail::alloc_destroyer<noinit_adaptor<A>, T> hold(a, p);
|
||||
for (std::size_t& i = hold.size(); i < n; ++i) {
|
||||
::new(static_cast<void*>(p + i)) T;
|
||||
}
|
||||
hold.size() = 0;
|
||||
}
|
||||
|
||||
template<class A, class T>
|
||||
inline void
|
||||
alloc_construct_n(A& a, T* p, std::size_t n, const T* l, std::size_t m)
|
||||
{
|
||||
detail::alloc_destroyer<A, T> hold(a, p);
|
||||
for (std::size_t& i = hold.size(); i < n; ++i) {
|
||||
::new(static_cast<void*>(p + i)) T(l[i % m]);
|
||||
}
|
||||
hold.size() = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
} /* boost */
|
||||
|
||||
#endif
|
@ -138,6 +138,9 @@ compile use_default_test.cpp ;
|
||||
|
||||
run default_allocator_test.cpp ;
|
||||
run noinit_adaptor_test.cpp ;
|
||||
run alloc_construct_test.cpp ;
|
||||
run alloc_construct_throws_test.cpp ;
|
||||
run alloc_construct_cxx11_test.cpp ;
|
||||
|
||||
lib lib_typeid : lib_typeid.cpp : <link>shared:<define>LIB_TYPEID_DYN_LINK=1 ;
|
||||
|
||||
|
79
test/alloc_construct_cxx11_test.cpp
Normal file
79
test/alloc_construct_cxx11_test.cpp
Normal file
@ -0,0 +1,79 @@
|
||||
/*
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include <boost/config.hpp>
|
||||
#if !defined(BOOST_NO_CXX11_ALLOCATOR)
|
||||
#include <boost/core/alloc_construct.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
class type {
|
||||
public:
|
||||
explicit type(int x)
|
||||
: value_(x) { }
|
||||
|
||||
int value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
static int count;
|
||||
|
||||
private:
|
||||
type(const type&);
|
||||
type& operator=(const type&);
|
||||
|
||||
int value_;
|
||||
};
|
||||
|
||||
int type::count = 0;
|
||||
|
||||
template<class T>
|
||||
struct creator {
|
||||
typedef T value_type;
|
||||
|
||||
creator() { }
|
||||
|
||||
template<class U>
|
||||
creator(const creator<U>&) { }
|
||||
|
||||
T* allocate(std::size_t size) {
|
||||
return static_cast<T*>(::operator new(sizeof(T) * size));
|
||||
}
|
||||
|
||||
void deallocate(T* ptr, std::size_t) {
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
template<class U, class V>
|
||||
void construct(U* ptr, const V& value) {
|
||||
::new(static_cast<void*>(ptr)) U(value + 1);
|
||||
++type::count;
|
||||
}
|
||||
|
||||
template<class U>
|
||||
void destroy(U* ptr) {
|
||||
ptr->~U();
|
||||
--type::count;
|
||||
}
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
creator<type> a;
|
||||
type* p = a.allocate(1);
|
||||
boost::alloc_construct(a, p, 1);
|
||||
BOOST_TEST_EQ(type::count, 1);
|
||||
BOOST_TEST_EQ(p->value(), 2);
|
||||
boost::alloc_destroy(a, p);
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
return boost::report_errors();
|
||||
}
|
||||
#else
|
||||
int main()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
119
test/alloc_construct_test.cpp
Normal file
119
test/alloc_construct_test.cpp
Normal file
@ -0,0 +1,119 @@
|
||||
/*
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include <boost/core/alloc_construct.hpp>
|
||||
#include <boost/core/default_allocator.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
class type {
|
||||
public:
|
||||
explicit type(int x = 0, int y = 0)
|
||||
: value_(x + y) {
|
||||
++count;
|
||||
}
|
||||
|
||||
type(const type& other)
|
||||
: value_(other.value_) {
|
||||
++count;
|
||||
}
|
||||
|
||||
~type() {
|
||||
--count;
|
||||
}
|
||||
|
||||
int value() const {
|
||||
return value_;
|
||||
}
|
||||
|
||||
static int count;
|
||||
|
||||
private:
|
||||
int value_;
|
||||
};
|
||||
|
||||
int type::count = 0;
|
||||
|
||||
void test_construct()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(1);
|
||||
boost::alloc_construct(a, p);
|
||||
BOOST_TEST_EQ(type::count, 1);
|
||||
BOOST_TEST_EQ(p->value(), 0);
|
||||
boost::alloc_destroy(a, p);
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
a.deallocate(p, 1);
|
||||
}
|
||||
|
||||
void test_construct_value()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(1);
|
||||
boost::alloc_construct(a, p, 1);
|
||||
BOOST_TEST_EQ(type::count, 1);
|
||||
BOOST_TEST_EQ(p->value(), 1);
|
||||
boost::alloc_destroy(a, p);
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
a.deallocate(p, 1);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
void test_construct_args()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(1);
|
||||
boost::alloc_construct(a, p, 1, 2);
|
||||
BOOST_TEST_EQ(type::count, 1);
|
||||
BOOST_TEST_EQ(p->value(), 3);
|
||||
boost::alloc_destroy(a, p);
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
a.deallocate(p, 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_construct_n()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(3);
|
||||
boost::alloc_construct_n(a, p, 3);
|
||||
BOOST_TEST_EQ(type::count, 3);
|
||||
BOOST_TEST_EQ(p[0].value(), 0);
|
||||
BOOST_TEST_EQ(p[1].value(), 0);
|
||||
BOOST_TEST_EQ(p[2].value(), 0);
|
||||
boost::alloc_destroy_n(a, p, 3);
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
a.deallocate(p, 3);
|
||||
}
|
||||
|
||||
void test_construct_n_list()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(3);
|
||||
type q(1);
|
||||
boost::alloc_construct_n(a, p, 3, &q, 1);
|
||||
BOOST_TEST_EQ(type::count, 4);
|
||||
BOOST_TEST_EQ(p[0].value(), 1);
|
||||
BOOST_TEST_EQ(p[1].value(), 1);
|
||||
BOOST_TEST_EQ(p[2].value(), 1);
|
||||
boost::alloc_destroy_n(a, p, 3);
|
||||
BOOST_TEST_EQ(type::count, 1);
|
||||
a.deallocate(p, 3);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_construct();
|
||||
test_construct_value();
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && \
|
||||
!defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
test_construct_args();
|
||||
#endif
|
||||
test_construct_n();
|
||||
test_construct_n_list();
|
||||
return boost::report_errors();
|
||||
}
|
46
test/alloc_construct_throws_test.cpp
Normal file
46
test/alloc_construct_throws_test.cpp
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2019 Glen Joseph Fernandes
|
||||
(glenjofe@gmail.com)
|
||||
|
||||
Distributed under the Boost Software License, Version 1.0.
|
||||
(http://www.boost.org/LICENSE_1_0.txt)
|
||||
*/
|
||||
#include <boost/core/alloc_construct.hpp>
|
||||
#include <boost/core/default_allocator.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
class type {
|
||||
public:
|
||||
type() {
|
||||
if (count == 4) {
|
||||
throw true;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
|
||||
~type() {
|
||||
--count;
|
||||
}
|
||||
|
||||
static int count;
|
||||
|
||||
private:
|
||||
type(const type&);
|
||||
type& operator=(const type&);
|
||||
};
|
||||
|
||||
int type::count = 0;
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::default_allocator<type> a;
|
||||
type* p = a.allocate(5);
|
||||
try {
|
||||
boost::alloc_construct_n(a, p, 5);
|
||||
BOOST_ERROR("construct_n did not throw");
|
||||
} catch (...) {
|
||||
BOOST_TEST_EQ(type::count, 0);
|
||||
}
|
||||
a.deallocate(p, 5);
|
||||
return boost::report_errors();
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user