From dc5406aa5a7534fda2666d4f123c145cb289110f Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Wed, 7 Nov 2012 14:42:10 +0000 Subject: [PATCH] Add support for make_shared of array of arrays. Correctly destroy elements and construct elements for the variadic template constructor variants. [SVN r81229] --- .../boost/smart_ptr/allocate_shared_array.hpp | 2 +- .../boost/smart_ptr/detail/array_deleter.hpp | 12 +-- .../boost/smart_ptr/detail/array_helper.hpp | 64 +++++++++++ include/boost/smart_ptr/make_shared_array.hpp | 2 +- test/allocate_shared_arrays_test.cpp | 75 +++++++++++++ test/make_shared_arrays_test.cpp | 101 ++++++++++++++++++ 6 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 include/boost/smart_ptr/detail/array_helper.hpp create mode 100644 test/allocate_shared_arrays_test.cpp create mode 100644 test/make_shared_arrays_test.cpp diff --git a/include/boost/smart_ptr/allocate_shared_array.hpp b/include/boost/smart_ptr/allocate_shared_array.hpp index 5d3f8cb..86d4065 100644 --- a/include/boost/smart_ptr/allocate_shared_array.hpp +++ b/include/boost/smart_ptr/allocate_shared_array.hpp @@ -9,7 +9,7 @@ #ifndef BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP #define BOOST_SMART_PTR_ALLOCATE_SHARED_ARRAY_HPP -#include +#include #include #include #include diff --git a/include/boost/smart_ptr/detail/array_deleter.hpp b/include/boost/smart_ptr/detail/array_deleter.hpp index 6f06401..de8b304 100644 --- a/include/boost/smart_ptr/detail/array_deleter.hpp +++ b/include/boost/smart_ptr/detail/array_deleter.hpp @@ -10,6 +10,7 @@ #define BOOST_SMART_PTR_DETAIL_ARRAY_DELETER_HPP #include +#include #include namespace boost { @@ -25,23 +26,20 @@ namespace boost { } void construct(T* memory, std::size_t count) { for (object = memory; size < count; size++) { - void* p1 = object + size; - ::new(p1) T(); + array_helper::create(object[size]); } } #if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) template void construct(T* memory, std::size_t count, Args&&... args) { for (object = memory; size < count; size++) { - void* p1 = object + size; - ::new(p1) T(args...); + array_helper::create(object[size], args...); } } #endif void construct_noinit(T* memory, std::size_t count) { for (object = memory; size < count; size++) { - void* p1 = object + size; - ::new(p1) T; + array_helper::create_noinit(object[size]); } } void operator()(T*) { @@ -50,7 +48,7 @@ namespace boost { private: void destroy() { while (size > 0) { - object[--size].~T(); + array_helper::destroy(object[--size]); } } std::size_t size; diff --git a/include/boost/smart_ptr/detail/array_helper.hpp b/include/boost/smart_ptr/detail/array_helper.hpp new file mode 100644 index 0000000..72b470c --- /dev/null +++ b/include/boost/smart_ptr/detail/array_helper.hpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2012 Glen Joseph Fernandes + * glenfe at live dot com + * + * Distributed under the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt + * or copy at http://boost.org/LICENSE_1_0.txt) + */ +#ifndef BOOST_SMART_PTR_DETAIL_ARRAY_HELPER_HPP +#define BOOST_SMART_PTR_DETAIL_ARRAY_HELPER_HPP + +namespace boost { + namespace detail { + template + struct array_helper { + static void destroy(T& value) { + value.~T(); + } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + template + static void create(T& value, Args... args) { + void* p1 = &value; + ::new(p1) T(args...); + } +#endif + }; +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + template + struct array_helper { + static void create(T value[N]) { + void* p1 = &value; + ::new(p1) T[N](); + } + static void create_noinit(T value[N]) { + void* p1 = &value; + ::new(p1) T[N]; + } + static void destroy(T value[N]) { + array_helper::destroy(value[N-1]); + array_helper::destroy(value); + } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + template + static void create(T value[N], Args... args) { + array_helper::create(value, args); + array_helper::create(value[N-1], args); + } +#endif + }; + template + struct array_helper { + static void destroy(T[]) { + } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + template + static void create(T[], Args...) { + } +#endif + }; +#endif + } +} + +#endif diff --git a/include/boost/smart_ptr/make_shared_array.hpp b/include/boost/smart_ptr/make_shared_array.hpp index b757fb7..b76cc73 100644 --- a/include/boost/smart_ptr/make_shared_array.hpp +++ b/include/boost/smart_ptr/make_shared_array.hpp @@ -9,7 +9,7 @@ #ifndef BOOST_SMART_PTR_MAKE_SHARED_ARRAY_HPP #define BOOST_SMART_PTR_MAKE_SHARED_ARRAY_HPP -#include +#include #include #include #include diff --git a/test/allocate_shared_arrays_test.cpp b/test/allocate_shared_arrays_test.cpp new file mode 100644 index 0000000..5bb48e5 --- /dev/null +++ b/test/allocate_shared_arrays_test.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2012 Glen Joseph Fernandes + * glenfe at live dot com + * + * Distributed under the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt + * or copy at http://boost.org/LICENSE_1_0.txt) + */ +#include +#include + +class type { +public: + static unsigned int instances; + explicit type(int = 0, int = 0) + : member() { + instances++; + } + ~type() { + instances--; + } +private: + type(const type&); + type& operator=(const type&); + double member; +}; + +unsigned int type::instances = 0; + +int main() { + { + boost::shared_ptr a1 = boost::allocate_shared(std::allocator(), 2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(a1[0][0][1] == 0); + BOOST_TEST(a1[0][1][0] == 0); + BOOST_TEST(a1[1][0][0] == 0); + } + { + boost::shared_ptr a1 = boost::allocate_shared(std::allocator(), 2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(a1[0][0][1] == 0); + BOOST_TEST(a1[0][1][0] == 0); + BOOST_TEST(a1[1][0][0] == 0); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::allocate_shared(std::allocator(), 2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + a1.reset(); + BOOST_TEST(type::instances == 0); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::allocate_shared(std::allocator(), 2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::allocate_shared(std::allocator(), 2, 1, 5); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + a1.reset(); + BOOST_TEST(type::instances == 0); + } +#endif + return boost::report_errors(); +} diff --git a/test/make_shared_arrays_test.cpp b/test/make_shared_arrays_test.cpp new file mode 100644 index 0000000..22fe447 --- /dev/null +++ b/test/make_shared_arrays_test.cpp @@ -0,0 +1,101 @@ +/* + * Copyright (c) 2012 Glen Joseph Fernandes + * glenfe at live dot com + * + * Distributed under the Boost Software License, + * Version 1.0. (See accompanying file LICENSE_1_0.txt + * or copy at http://boost.org/LICENSE_1_0.txt) + */ +#include +#include + +class type { +public: + static unsigned int instances; + explicit type(int = 0, int = 0) + : member() { + instances++; + } + ~type() { + instances--; + } +private: + type(const type&); + type& operator=(const type&); + double member; +}; + +unsigned int type::instances = 0; + +int main() { + { + boost::shared_ptr a1 = boost::make_shared(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(a1[0][0][1] == 0); + BOOST_TEST(a1[0][1][0] == 0); + BOOST_TEST(a1[1][0][0] == 0); + } + { + boost::shared_ptr a1 = boost::make_shared(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(a1[0][0][1] == 0); + BOOST_TEST(a1[0][1][0] == 0); + BOOST_TEST(a1[1][0][0] == 0); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::make_shared(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + a1.reset(); + BOOST_TEST(type::instances == 0); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::make_shared(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + } +#if defined(BOOST_HAS_VARIADIC_TMPL) && defined(BOOST_HAS_RVALUE_REFS) + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::make_shared(2, 1, 5); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + a1.reset(); + BOOST_TEST(type::instances == 0); + } +#endif + { + boost::shared_ptr a1 = boost::make_shared_noinit(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + } + { + boost::shared_ptr a1 = boost::make_shared_noinit(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::make_shared_noinit(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + a1.reset(); + BOOST_TEST(type::instances == 0); + } + BOOST_TEST(type::instances == 0); + { + boost::shared_ptr a1 = boost::make_shared_noinit(2); + BOOST_TEST(a1.get() != 0); + BOOST_TEST(a1.use_count() == 1); + BOOST_TEST(type::instances == 8); + } + return boost::report_errors(); +}