From 6d5f554baa9a148d39796577b6f4f254a353c10b Mon Sep 17 00:00:00 2001 From: Karolin Varner Date: Thu, 17 Dec 2015 12:35:14 +0100 Subject: [PATCH 01/18] Reuse code for plain and shared in ptr cast tests --- test/pointer_cast_test.cpp | 36 ++++++++++++++---------------------- 1 file changed, 14 insertions(+), 22 deletions(-) diff --git a/test/pointer_cast_test.cpp b/test/pointer_cast_test.cpp index bd25dd1..ae036fb 100644 --- a/test/pointer_cast_test.cpp +++ b/test/pointer_cast_test.cpp @@ -104,33 +104,25 @@ bool check_const_pointer_cast(const BasePtr &ptr) const_cast(const_cast(boost::get_pointer(ptr))); } +template +void check_all_casts(const BasePtr &ptr) +{ +#if !defined( BOOST_NO_RTTI ) + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); +#endif + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); +} + } int main() { - { - // Try casts with shared_ptr + boost::shared_ptr boost_shared(new derived); + base *plain = boost_shared.get(); - boost::shared_ptr ptr(new derived); - -#if !defined( BOOST_NO_RTTI ) - BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); -#endif - BOOST_TEST( check_static_pointer_cast( ptr ) ); - BOOST_TEST( check_const_pointer_cast( ptr ) ); - } - - { - // Try casts with raw pointer - - boost::scoped_ptr ptr(new derived); - -#if !defined( BOOST_NO_RTTI ) - BOOST_TEST( check_dynamic_pointer_cast( ptr.get() ) ); -#endif - BOOST_TEST( check_static_pointer_cast( ptr.get() ) ); - BOOST_TEST( check_const_pointer_cast( ptr.get() ) ); - } + check_all_casts(boost_shared); + check_all_casts(plain); return boost::report_errors(); } From 2185c4f005e16073f3f91328ca7bee493b38dd56 Mon Sep 17 00:00:00 2001 From: Karolin Varner Date: Thu, 17 Dec 2015 12:46:41 +0100 Subject: [PATCH 02/18] Fix a documentation typo --- shared_ptr.htm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/shared_ptr.htm b/shared_ptr.htm index 5c756f8..1cd0bc4 100644 --- a/shared_ptr.htm +++ b/shared_ptr.htm @@ -222,7 +222,7 @@ void bad() shared_ptr<T> dynamic_pointer_cast(shared_ptr<U> const & r); // never throws template<class T, class U> - shared_ptr<T> reinterpet_pointer_cast(shared_ptr<U> const & r); // never throws + shared_ptr<T> reinterpret_pointer_cast(shared_ptr<U> const & r); // never throws template<class E, class T, class Y> std::basic_ostream<E, T> & operator<< (std::basic_ostream<E, T> & os, shared_ptr<Y> const & p); From 6b787f1cec04c1022b28e0519073294870ccca99 Mon Sep 17 00:00:00 2001 From: Karolin Varner Date: Thu, 17 Dec 2015 13:47:00 +0100 Subject: [PATCH 03/18] Add overloads for std::shared_ptr to pointer casts --- include/boost/pointer_cast.hpp | 30 ++++++++ pointer_cast.html | 16 +++- test/Jamfile.v2 | 1 + test/cpp11_pointer_cast_test.cpp | 124 +++++++++++++++++++++++++++++++ 4 files changed, 169 insertions(+), 2 deletions(-) create mode 100644 test/cpp11_pointer_cast_test.cpp diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp index 6e532eb..3c65cac 100644 --- a/include/boost/pointer_cast.hpp +++ b/include/boost/pointer_cast.hpp @@ -42,4 +42,34 @@ inline T* reinterpret_pointer_cast(U *ptr) } // namespace boost +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + +#include + +namespace boost { + +//static_pointer_cast overload for std::shared_ptr +using std::static_pointer_cast; + +//dynamic_pointer_cast overload for std::shared_ptr +using std::dynamic_pointer_cast; + +//const_pointer_cast overload for std::shared_ptr +using std::const_pointer_cast; + +//reinterpret_pointer_cast overload for std::shared_ptr +template std::shared_ptr reinterpret_pointer_cast(const std::shared_ptr & r ) BOOST_NOEXCEPT +{ + (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) ); + + typedef typename std::shared_ptr::element_type E; + + E * p = reinterpret_cast< E* >( r.get() ); + return std::shared_ptr( r, p ); +} + +} // namespace boost + +#endif // #if !defined( BOOST_NO_CXX11_SMART_PTR ) + #endif //BOOST_POINTER_CAST_HPP diff --git a/pointer_cast.html b/pointer_cast.html index 2ab0859..4e52cf0 100644 --- a/pointer_cast.html +++ b/pointer_cast.html @@ -9,7 +9,7 @@ width="277" align="middle" border="0">pointer_cast

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast boost::reinterpret_pointer_cast boost::const_pointer_cast) - provide a way to write generic pointer castings for raw pointers. The functions + provide a way to write generic pointer castings for raw pointers and std::shared_ptr. The functions are defined in boost/pointer_cast.hpp.

There is test/example code in pointer_cast_test.cpp.

Rationale

@@ -23,7 +23,7 @@ template<class T, class U>

Pointer cast functions from boost/pointer_cast.hpp are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, boost::reinterpret_pointer_cast and boost::const_pointer_cast - for raw pointers. This way when developing pointer type independent classes, + for raw pointers and std::shared_ptr. This way when developing pointer type independent classes, for example, memory managers or shared memory compatible classes, the same code can be used for raw and smart pointers.

Synopsis

@@ -46,6 +46,18 @@ inline T* const_pointer_cast(U *ptr) template<class T, class U> inline T* reinterpret_pointer_cast(U *ptr) { return reinterpret_cast<T*>(ptr); } + +template<class T, class U> +inline std::shared_ptr<U> static_pointer_cast(std::shared_ptr<T> ptr); + +template<class T, class U> +inline std::shared_ptr<U> dynamic_pointer_cast(std::shared_ptr<T> ptr); + +template<class T, class U> +inline std::shared_ptr<U> const_pointer_cast(std::shared_ptr<T> ptr); + +template<class T, class U> +inline std::shared_ptr<U> reinterpret_pointer_cast(std::shared_ptr<T> ptr); } // namespace boost diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d965bfd..6eb4c89 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -29,6 +29,7 @@ import testing ; [ compile-fail shared_ptr_compare_fail.cpp ] [ run shared_ptr_alloc2_test.cpp ] [ run pointer_cast_test.cpp ] + [ run cpp11_pointer_cast_test.cpp ] [ compile pointer_to_other_test.cpp ] [ run auto_ptr_rv_test.cpp ] [ run shared_ptr_alias_test.cpp ] diff --git a/test/cpp11_pointer_cast_test.cpp b/test/cpp11_pointer_cast_test.cpp new file mode 100644 index 0000000..a937708 --- /dev/null +++ b/test/cpp11_pointer_cast_test.cpp @@ -0,0 +1,124 @@ +// +// cpp11_pointer_cast_test.cpp - a test for boost/pointer_cast.hpp with std::shared_ptr +// +// Copyright (c) 2016 Karolin Varner +// +// Distributed under the Boost Software License, Version 1.0. (See +// accompanying file LICENSE_1_0.txt or copy at +// http://www.boost.org/LICENSE_1_0.txt) +// + +#include +#include +#include +#include + +#include + +namespace +{ + +// Let's create these inheritance relationship: +// +// base base2 +// | | +// derived +// | +// derived_derived +// + +class base +{ + public: + virtual ~base(){} + int filler [5]; +}; + +class base2 +{ +public: + + virtual ~base2(){} + int filler [5]; +}; + +class derived + : public base, public base2 +{ + int filler [5]; +}; + +class derived_derived + : public derived +{ + int filler [5]; +}; + +// And now some simple check functions + +#if !defined( BOOST_NO_RTTI ) + +template +bool check_dynamic_pointer_cast(const BasePtr &ptr) +{ + //Check that dynamic_pointer_cast versus dynamic_cast + return + //Correct cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Correct cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)) + && + //Incorrect cast with dynamic_pointer_cast + boost::get_pointer(boost::dynamic_pointer_cast(ptr)) == + //Incorrect cast with dynamic_cast + dynamic_cast(boost::get_pointer(ptr)); +} + +#endif + +template +bool check_static_pointer_cast(const BasePtr &ptr) +{ + return + //Cast base -> derived -> base2 using static_pointer_cast + boost::get_pointer( + boost::static_pointer_cast( + boost::static_pointer_cast(ptr))) == + //Now the same with static_cast + static_cast(static_cast(boost::get_pointer(ptr))); +} + +template +bool check_const_pointer_cast(const BasePtr &ptr) +{ + return + //Unconst and const again using const_pointer_cast + boost::get_pointer( + boost::const_pointer_cast + (boost::const_pointer_cast(ptr))) == + //Now the same with const_cast + const_cast(const_cast(boost::get_pointer(ptr))); +} + +template +void check_all_casts(const BasePtr &ptr) +{ +#if !defined( BOOST_NO_RTTI ) + BOOST_TEST( check_dynamic_pointer_cast( ptr ) ); +#endif + BOOST_TEST( check_static_pointer_cast( ptr ) ); + BOOST_TEST( check_const_pointer_cast( ptr ) ); +} + +} + +int main() +{ +#if !defined( BOOST_NO_CXX11_SMART_PTR ) + std::shared_ptr std_shared(new derived); + check_all_casts(std_shared); +#endif + + return boost::report_errors(); +} + From ce52fb10450c44c12ae9cd5560b5c88c3b3ea798 Mon Sep 17 00:00:00 2001 From: Karolin Varner Date: Thu, 17 Dec 2015 15:32:30 +0100 Subject: [PATCH 04/18] pointer_casts with move semantics for unique_ptr --- include/boost/pointer_cast.hpp | 48 ++++++++++++ pointer_cast.html | 67 ++++++++++++++++- test/cpp11_pointer_cast_test.cpp | 122 ++++++++++++++++++++++++++++--- 3 files changed, 222 insertions(+), 15 deletions(-) diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp index 3c65cac..6a5af8b 100644 --- a/include/boost/pointer_cast.hpp +++ b/include/boost/pointer_cast.hpp @@ -7,6 +7,8 @@ // ////////////////////////////////////////////////////////////////////////////// +#include + #ifndef BOOST_POINTER_CAST_HPP #define BOOST_POINTER_CAST_HPP @@ -44,10 +46,27 @@ inline T* reinterpret_pointer_cast(U *ptr) #if !defined( BOOST_NO_CXX11_SMART_PTR ) +#include + +#include +#include +#include + #include namespace boost { +namespace detail { + +template +void assert_safe_moving_upcast() { + BOOST_STATIC_ASSERT_MSG( !(boost::is_base_of::value && !boost::is_pod::value && !boost::has_virtual_destructor::value) + , "Upcast from a non-POD child to a base without virtual destructor is unsafe, because the child's destructor " + "will not be called when the base pointer is deleted. Consider using shared_ptr for such types."); +} + +} + //static_pointer_cast overload for std::shared_ptr using std::static_pointer_cast; @@ -68,6 +87,35 @@ template std::shared_ptr reinterpret_pointer_cast(const std return std::shared_ptr( r, p ); } +//static_pointer_cast overload for std::unique_ptr +template std::unique_ptr static_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + detail::assert_safe_moving_upcast(); + return std::unique_ptr( static_cast( r.release() ) ); +} + +//dynamic_pointer_cast overload for std::unique_ptr +template std::unique_ptr dynamic_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + detail::assert_safe_moving_upcast(); + + T * p = dynamic_cast( r.get() ); + if( p ) r.release(); + return std::unique_ptr( p ); +} + +//const_pointer_cast overload for std::unique_ptr +template std::unique_ptr const_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + return std::unique_ptr( const_cast( r.release() ) ); +} + +//reinterpret_pointer_cast overload for std::unique_ptr +template std::unique_ptr reinterpret_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT +{ + return std::unique_ptr( reinterpret_cast( r.release() ) ); +} + } // namespace boost #endif // #if !defined( BOOST_NO_CXX11_SMART_PTR ) diff --git a/pointer_cast.html b/pointer_cast.html index 4e52cf0..f0c7fa2 100644 --- a/pointer_cast.html +++ b/pointer_cast.html @@ -9,7 +9,7 @@ width="277" align="middle" border="0">pointer_cast

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast boost::reinterpret_pointer_cast boost::const_pointer_cast) - provide a way to write generic pointer castings for raw pointers and std::shared_ptr. The functions + provide a way to write generic pointer castings for raw pointers, std::shared_ptr and std::unique_ptr. The functions are defined in boost/pointer_cast.hpp.

There is test/example code in pointer_cast_test.cpp.

Rationale

@@ -23,7 +23,7 @@ template<class T, class U>

Pointer cast functions from boost/pointer_cast.hpp are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, boost::reinterpret_pointer_cast and boost::const_pointer_cast - for raw pointers and std::shared_ptr. This way when developing pointer type independent classes, + for raw pointers, std::shared_ptr and std::unique_ptr. This way when developing pointer type independent classes, for example, memory managers or shared memory compatible classes, the same code can be used for raw and smart pointers.

Synopsis

@@ -58,12 +58,71 @@ inline std::shared_ptr<U> const_pointer_cast(std::shared_ptr<T> ptr) template<class T, class U> inline std::shared_ptr<U> reinterpret_pointer_cast(std::shared_ptr<T> ptr); + +template<class T, class U> +inline std::unique_ptr<U> static_pointer_cast(std::unique_ptr<T> &&ptr); + +template<class T, class U> +inline std::unique_ptr<U> dynamic_pointer_cast(std::unique_ptr<T> &&ptr); + +template<class T, class U> +inline std::unique_ptr<U> const_pointer_cast(std::unique_ptr<T> &&ptr); + +template<class T, class U> +inline std::unique_ptr<U> reinterpret_pointer_cast(std::unique_ptr<T> &&ptr); } // namespace boost -

As you can see from the above synopsis, the pointer cast functions are just - wrappers around standard C++ cast operators.

+

As you can see from the above synopsis, the pointer cast functions for raw pointers are just + wrappers around standard C++ cast operators.

+ +

Memory Safety

+

It is possible to write unsafe code, when upcasting to a base type without virtual destructor. + Consider the following example:

+
+#include <memory>
+#include <utility>
+#include <boost/pointer_cast.hpp>
+#include <boost/make_unique.hpp>
+
+int destructed = 0;
+
+struct base {
+  ~base() {
+    // ...
+  }
+};
+
+struct child : base {
+  virtual ~child() {
+    destructed++;
+  }
+}
+
+int main() {
+  {
+    std::unique_ptr tmp = boost::make_unique();
+    std::unique_ptr sink = boost::static_pointer_cast( std::move(tmp) );
+  }
+
+  // child::~child was never called
+  assert(destructed == 0);
+
+  return 0;
+}
+
+

In this example, the child destructor child::~child was never called, because the child* in tmp + was downcast to a base* and moved into sink. The destructor of tmp did essentially nothing, because + it contained nullptr during destruction; sink deleted the pointer, but since base::~base is non-virtual + the child destructor was never called.

+

boost::static_pointer_cast and boost::dynamic_pointer_cast for std::unique_ptr prevent the above scenario + by raising a compiler error when such a cast is detected.

+

The overloads for std::shared_ptr and boost::shared_ptr are not prone to this problem, since they internally + always store the original pointer with the original type.

+

The plain pointer casts are in principle also prone to that problem, but it is assumed that raw pointers + are non-owning, so no checking is performed.

+

Example

diff --git a/test/cpp11_pointer_cast_test.cpp b/test/cpp11_pointer_cast_test.cpp
index a937708..a9361c3 100644
--- a/test/cpp11_pointer_cast_test.cpp
+++ b/test/cpp11_pointer_cast_test.cpp
@@ -1,5 +1,5 @@
 //
-//  cpp11_pointer_cast_test.cpp - a test for boost/pointer_cast.hpp with std::shared_ptr
+//  cpp11_pointer_cast_test.cpp - a test for boost/pointer_cast.hpp with std::shared_ptr and std::unique_ptr
 //
 //  Copyright (c) 2016 Karolin Varner
 //
@@ -8,12 +8,28 @@
 // http://www.boost.org/LICENSE_1_0.txt)
 //
 
-#include 
 #include 
+
+#include 
 #include 
 #include 
+#include 
 
 #include 
+#include 
+#include 
+
+#if defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) \
+ || defined( BOOST_NO_CXX11_HDR_FUNCTIONAL ) \
+ || defined( BOOST_NO_CXX11_HDR_UTILITY ) \
+ || defined( BOOST_NO_CXX11_LAMBDAS ) \
+ || defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
+
+// We expect all the features or none of the features to be
+// available, since we should be on C++11
+int main() { return 0; }
+
+#else
 
 namespace
 {
@@ -43,7 +59,7 @@ public:
 };
 
 class derived
-   : public base, public base2 
+   : public base, public base2
 {
     int filler [5];
 };
@@ -66,7 +82,7 @@ bool check_dynamic_pointer_cast(const BasePtr &ptr)
    //Correct cast with dynamic_pointer_cast
    boost::get_pointer(boost::dynamic_pointer_cast(ptr)) ==
       //Correct cast with dynamic_cast
-      dynamic_cast(boost::get_pointer(ptr)) 
+      dynamic_cast(boost::get_pointer(ptr))
    &&
    //Incorrect cast with dynamic_pointer_cast
    boost::get_pointer(boost::dynamic_pointer_cast(ptr)) ==
@@ -91,7 +107,7 @@ bool check_static_pointer_cast(const BasePtr &ptr)
 template 
 bool check_const_pointer_cast(const BasePtr &ptr)
 {
-   return   
+   return
    //Unconst and const again using const_pointer_cast
    boost::get_pointer(
       boost::const_pointer_cast
@@ -101,7 +117,7 @@ bool check_const_pointer_cast(const BasePtr &ptr)
 }
 
 template 
-void check_all_casts(const BasePtr &ptr)
+void check_all_copy_casts(const BasePtr &ptr)
 {
 #if !defined( BOOST_NO_RTTI )
    BOOST_TEST( check_dynamic_pointer_cast( ptr ) );
@@ -110,15 +126,99 @@ void check_all_casts(const BasePtr &ptr)
    BOOST_TEST( check_const_pointer_cast( ptr ) );
 }
 
+
+#if !defined( BOOST_NO_RTTI )
+
+template 
+bool check_dynamic_moving_pointer_cast(std::function f)
+{
+   BasePtr smart1 = f(), smart2 = f();
+   derived* expect1 = dynamic_cast(boost::get_pointer(smart1));
+   derived_derived* expect2 = dynamic_cast(boost::get_pointer(smart2));
+   //Check that dynamic_pointer_cast versus dynamic_cast
+   return
+   //Correct cast with dynamic_pointer_cast
+   boost::get_pointer(boost::dynamic_pointer_cast( std::move(smart1) )) == expect1
+   &&
+   //Incorrect cast with dynamic_pointer_cast
+   boost::get_pointer(boost::dynamic_pointer_cast( std::move(smart2) )) == expect2;
+}
+
+#endif
+
+template 
+bool check_static_moving_pointer_cast(std::function f)
+{
+   BasePtr smart = f();
+   base2 *expect = static_cast(static_cast(boost::get_pointer(smart)));
+
+   return
+   //Cast base -> derived -> base2 using static_pointer_cast
+   boost::get_pointer(
+            boost::static_pointer_cast(
+               boost::static_pointer_cast( std::move(smart) ))) ==
+   //Now the same with static_cast
+   expect;
+}
+
+template 
+bool check_const_moving_pointer_cast(std::function f)
+{
+   BasePtr smart = f();
+   const base *expect = const_cast(const_cast(boost::get_pointer(smart)));
+   return
+   //Unconst and const again using const_pointer_cast
+   boost::get_pointer(
+      boost::const_pointer_cast
+         (boost::const_pointer_cast( std::move(smart) ))) ==
+   //Now the same with const_cast
+   expect;
+}
+
+template 
+void check_all_moving_casts(std::function f) {
+#if !defined( BOOST_NO_RTTI )
+   BOOST_TEST( check_dynamic_moving_pointer_cast( f ) );
+#endif
+   BOOST_TEST( check_static_moving_pointer_cast( f ) );
+   BOOST_TEST( check_const_moving_pointer_cast( f ) );
+}
+
 }
 
 int main()
 {
-#if !defined( BOOST_NO_CXX11_SMART_PTR )
+
    std::shared_ptr std_shared(new derived);
-   check_all_casts(std_shared);
-#endif
+   boost::shared_ptr boost_shared(new derived);
+   base *plain = boost_shared.get();
 
-   return boost::report_errors();
+   // plain & boost::shared_ptr moving pointer_cast checks; there
+   // is no specific handleing for those types at the moment; this
+   // test just makes sure they won't break when std::move() is used
+   // in generic code
+
+   check_all_moving_casts>([&boost_shared]() {
+       return boost_shared;
+   });
+
+   check_all_moving_casts([plain]() {
+       return plain;
+   });
+
+   // std::shared_ptr casts
+
+   check_all_copy_casts(std_shared);
+   check_all_moving_casts>([&std_shared]() {
+       return std_shared;
+   });
+
+   // std::unique_ptr casts
+
+   check_all_moving_casts>([]() {
+       return std::unique_ptr(new derived);
+   });
+
+    return boost::report_errors();
 }
-
+#endif

From de38a735ea7793f9c7e747e49e3ce3900b92ab46 Mon Sep 17 00:00:00 2001
From: Giel van Schijndel 
Date: Sun, 24 Jul 2016 14:38:21 +0200
Subject: [PATCH 05/18] boost::make_shared: use Constructor Forwarding on C++03

Use Boost.Move's move emulation and documented Constructor Forwarding
technique to provide (partial) constructor forwarding on compilers that
don't support r-value references.

This allows constructing types taking movable-but-not-copyable types as
constructor arguments. Additionally it's generally more efficient for
movable-and-copyable types, but that's just a nice-to-have.
---
 .../boost/smart_ptr/make_shared_object.hpp    | 658 +++++-------------
 1 file changed, 164 insertions(+), 494 deletions(-)

diff --git a/include/boost/smart_ptr/make_shared_object.hpp b/include/boost/smart_ptr/make_shared_object.hpp
index 62372fa..3bc78ee 100644
--- a/include/boost/smart_ptr/make_shared_object.hpp
+++ b/include/boost/smart_ptr/make_shared_object.hpp
@@ -13,6 +13,8 @@
 //  for documentation.
 
 #include 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -338,466 +340,10 @@ template< class T, class A > typename boost::detail::sp_if_not_array< T >::type
     return boost::shared_ptr< T >( pt, pt2 );
 }
 
-#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
-
-// For example MSVC 10.0
-
-template< class T, class A1 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4, class A5 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4, class A5 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4, class A5, class A6 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 ), 
-        boost::detail::sp_forward( a8 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 ), 
-        boost::detail::sp_forward( a8 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T(
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 ), 
-        boost::detail::sp_forward( a8 ), 
-        boost::detail::sp_forward( a9 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 && a1, A2 && a2, A3 && a3, A4 && a4, A5 && a5, A6 && a6, A7 && a7, A8 && a8, A9 && a9 )
-{
-    boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
-
-    boost::detail::sp_ms_deleter< T > * pd = static_cast *>( pt._internal_get_untyped_deleter() );
-
-    void * pv = pd->address();
-
-    ::new( pv ) T( 
-        boost::detail::sp_forward( a1 ), 
-        boost::detail::sp_forward( a2 ), 
-        boost::detail::sp_forward( a3 ), 
-        boost::detail::sp_forward( a4 ), 
-        boost::detail::sp_forward( a5 ), 
-        boost::detail::sp_forward( a6 ), 
-        boost::detail::sp_forward( a7 ), 
-        boost::detail::sp_forward( a8 ), 
-        boost::detail::sp_forward( a9 )
-        );
-
-    pd->set_initialized();
-
-    T * pt2 = static_cast< T* >( pv );
-
-    boost::detail::sp_enable_shared_from_this( &pt, pt2, pt2 );
-    return boost::shared_ptr< T >( pt, pt2 );
-}
-
-#else // !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
-
 // C++03 version
 
 template< class T, class A1 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -805,7 +351,10 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1 )
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1 );
+    ::new( pv ) T(
+        boost::forward( a1 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -815,7 +364,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1 )
 }
 
 template< class T, class A, class A1 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -823,7 +372,10 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1 );
+    ::new( pv ) T(
+        boost::forward( a1 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -833,7 +385,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -841,7 +393,11 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -851,7 +407,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -859,7 +415,11 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -869,7 +429,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -877,7 +437,12 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -887,7 +452,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -895,7 +460,12 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -905,7 +475,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -913,7 +483,13 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -923,7 +499,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -931,7 +507,13 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -941,7 +523,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4, class A5 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -949,7 +531,14 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -959,7 +548,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4, class A5 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -967,7 +556,14 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -977,7 +573,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4, class A5, class A6 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -985,7 +581,15 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -995,7 +599,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -1003,7 +607,15 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1013,7 +625,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -1021,7 +633,16 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1031,7 +652,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -1039,7 +660,16 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1049,7 +679,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -1057,7 +687,17 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 ),
+        boost::forward( a8 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1067,7 +707,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -1075,7 +715,17 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 ),
+        boost::forward( a8 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1085,7 +735,7 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 }
 
 template< class T, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
-typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 )
+typename boost::detail::sp_if_not_array< T >::type make_shared( BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8, BOOST_FWD_REF(A9) a9 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ) );
 
@@ -1093,7 +743,18 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 ),
+        boost::forward( a8 ),
+        boost::forward( a9 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1103,7 +764,7 @@ typename boost::detail::sp_if_not_array< T >::type make_shared( A1 const & a1, A
 }
 
 template< class T, class A, class A1, class A2, class A3, class A4, class A5, class A6, class A7, class A8, class A9 >
-typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, A1 const & a1, A2 const & a2, A3 const & a3, A4 const & a4, A5 const & a5, A6 const & a6, A7 const & a7, A8 const & a8, A9 const & a9 )
+typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2, BOOST_FWD_REF(A3) a3, BOOST_FWD_REF(A4) a4, BOOST_FWD_REF(A5) a5, BOOST_FWD_REF(A6) a6, BOOST_FWD_REF(A7) a7, BOOST_FWD_REF(A8) a8, BOOST_FWD_REF(A9) a9 )
 {
     boost::shared_ptr< T > pt( static_cast< T* >( 0 ), BOOST_SP_MSD( T ), a );
 
@@ -1111,7 +772,18 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
 
     void * pv = pd->address();
 
-    ::new( pv ) T( a1, a2, a3, a4, a5, a6, a7, a8, a9 );
+    ::new( pv ) T(
+        boost::forward( a1 ),
+        boost::forward( a2 ),
+        boost::forward( a3 ),
+        boost::forward( a4 ),
+        boost::forward( a5 ),
+        boost::forward( a6 ),
+        boost::forward( a7 ),
+        boost::forward( a8 ),
+        boost::forward( a9 )
+        );
+
     pd->set_initialized();
 
     T * pt2 = static_cast< T* >( pv );
@@ -1120,8 +792,6 @@ typename boost::detail::sp_if_not_array< T >::type allocate_shared( A const & a,
     return boost::shared_ptr< T >( pt, pt2 );
 }
 
-#endif // !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
-
 #endif // !defined( BOOST_NO_CXX11_VARIADIC_TEMPLATES ) && !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
 
 #undef BOOST_SP_MSD

From 20fedcff2ca3143503ec4e876d47745ab0ec7b0c Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sun, 28 Aug 2016 21:28:21 +0300
Subject: [PATCH 06/18] Use  by default when BOOST_NO_CXX11_HDR_ATOMIC
 is not defined

---
 include/boost/smart_ptr/detail/atomic_count.hpp    | 3 +++
 include/boost/smart_ptr/detail/sp_counted_base.hpp | 3 +++
 include/boost/smart_ptr/detail/spinlock.hpp        | 3 +++
 3 files changed, 9 insertions(+)

diff --git a/include/boost/smart_ptr/detail/atomic_count.hpp b/include/boost/smart_ptr/detail/atomic_count.hpp
index 8aefd44..6e4f71a 100644
--- a/include/boost/smart_ptr/detail/atomic_count.hpp
+++ b/include/boost/smart_ptr/detail/atomic_count.hpp
@@ -73,6 +73,9 @@
 #elif defined( BOOST_DISABLE_THREADS ) && !defined( BOOST_SP_ENABLE_THREADS ) && !defined( BOOST_DISABLE_WIN32 )
 # include 
 
+#elif !defined( BOOST_NO_CXX11_HDR_ATOMIC )
+# include 
+
 #elif defined( __GNUC__ ) && ( defined( __i386__ ) || defined( __x86_64__ ) ) && !defined( __PATHSCALE__ )
 # include 
 
diff --git a/include/boost/smart_ptr/detail/sp_counted_base.hpp b/include/boost/smart_ptr/detail/sp_counted_base.hpp
index 0addf07..851ef19 100644
--- a/include/boost/smart_ptr/detail/sp_counted_base.hpp
+++ b/include/boost/smart_ptr/detail/sp_counted_base.hpp
@@ -44,6 +44,9 @@
 #elif defined( BOOST_SP_HAS_CLANG_C11_ATOMICS )
 # include 
 
+#elif !defined( BOOST_NO_CXX11_HDR_ATOMIC )
+# include 
+
 #elif defined( __SNC__ )
 # include 
 
diff --git a/include/boost/smart_ptr/detail/spinlock.hpp b/include/boost/smart_ptr/detail/spinlock.hpp
index 19f93d7..0b618df 100644
--- a/include/boost/smart_ptr/detail/spinlock.hpp
+++ b/include/boost/smart_ptr/detail/spinlock.hpp
@@ -43,6 +43,9 @@
 #elif defined( BOOST_SP_USE_PTHREADS )
 #  include 
 
+#elif !defined( BOOST_NO_CXX11_HDR_ATOMIC )
+#  include 
+
 #elif defined(__GNUC__) && defined( __arm__ ) && !defined( __thumb__ )
 #  include 
 

From 3b9ae9fd5f02a7f91d7cbd05a6cb4a7ce7e63755 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sun, 28 Aug 2016 22:01:59 +0300
Subject: [PATCH 07/18] Switch from msvc-12.0 to msvc-14.0 on Appveyor

---
 appveyor.yml | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/appveyor.yml b/appveyor.yml
index 1fbbf38..8132b0d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -41,4 +41,4 @@ install:
 build: off
 
 test_script:
-  - b2 libs/smart_ptr/test toolset=msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0
+  - b2 libs/smart_ptr/test toolset=msvc-9.0,msvc-10.0,msvc-11.0,msvc-14.0

From e8daeaee1c4065a3e711a6fe67ded7268a58e15e Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sun, 28 Aug 2016 22:37:10 +0300
Subject: [PATCH 08/18] Enable Travis notifications on success

---
 .travis.yml | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/.travis.yml b/.travis.yml
index 7cc89de..1b0d775 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -46,3 +46,7 @@ script:
   - TOOLSET=gcc,clang
   - if [ $TRAVIS_OS_NAME == osx ]; then TOOLSET=clang; fi
   - ./b2 libs/smart_ptr/test toolset=$TOOLSET
+
+notifications:
+  email:
+    on_success: always

From 70367e848e3367de8a314299dc3e54b7af791d27 Mon Sep 17 00:00:00 2001
From: Nikita Kniazev 
Date: Wed, 31 Aug 2016 17:32:09 +0300
Subject: [PATCH 09/18] Suppress weak vtables warnings

---
 include/boost/smart_ptr/bad_weak_ptr.hpp                 | 9 +++++++++
 include/boost/smart_ptr/detail/sp_counted_base_clang.hpp | 9 +++++++++
 2 files changed, 18 insertions(+)

diff --git a/include/boost/smart_ptr/bad_weak_ptr.hpp b/include/boost/smart_ptr/bad_weak_ptr.hpp
index 3e0a1b7..582fad8 100644
--- a/include/boost/smart_ptr/bad_weak_ptr.hpp
+++ b/include/boost/smart_ptr/bad_weak_ptr.hpp
@@ -36,6 +36,11 @@ namespace boost
 # pragma option push -pc
 #endif
 
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
 class bad_weak_ptr: public std::exception
 {
 public:
@@ -46,6 +51,10 @@ public:
     }
 };
 
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
 #if defined(__BORLANDC__) && __BORLANDC__ <= 0x564
 # pragma option pop
 #endif
diff --git a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp
index c66b985..7598495 100644
--- a/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp
+++ b/include/boost/smart_ptr/detail/sp_counted_base_clang.hpp
@@ -58,6 +58,11 @@ inline boost::int_least32_t atomic_conditional_increment( atomic_int_least32_t *
     }    
 }
 
+#if defined(__clang__)
+# pragma clang diagnostic push
+# pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
 class sp_counted_base
 {
 private:
@@ -133,6 +138,10 @@ public:
     }
 };
 
+#if defined(__clang__)
+# pragma clang diagnostic pop
+#endif
+
 } // namespace detail
 
 } // namespace boost

From 840e9fc96e9e1672f93c785ee78b5edc4bc4af01 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Fri, 2 Sep 2016 20:13:15 +0300
Subject: [PATCH 10/18] Apply MIPS16 patch from ticket #12418

---
 include/boost/smart_ptr/detail/sp_counted_base.hpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/include/boost/smart_ptr/detail/sp_counted_base.hpp b/include/boost/smart_ptr/detail/sp_counted_base.hpp
index 851ef19..83ede23 100644
--- a/include/boost/smart_ptr/detail/sp_counted_base.hpp
+++ b/include/boost/smart_ptr/detail/sp_counted_base.hpp
@@ -68,7 +68,7 @@
 #elif defined( __GNUC__ ) && ( defined( __powerpc__ ) || defined( __ppc__ ) || defined( __ppc ) ) && !defined(__PATHSCALE__) && !defined( _AIX )
 # include 
 
-#elif defined( __GNUC__ ) && ( defined( __mips__ ) || defined( _mips ) ) && !defined(__PATHSCALE__)
+#elif defined( __GNUC__ ) && ( defined( __mips__ ) || defined( _mips ) ) && !defined(__PATHSCALE__) && !defined( __mips16 )
 # include 
 
 #elif defined( BOOST_SP_HAS_SYNC )

From 80597b379e5a1f35031ebcb749a28e248d77b8e0 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 13:47:05 +0300
Subject: [PATCH 11/18] Copy repo instead of doing a checkout, for pull
 requests.

---
 .travis.yml  | 10 ++++------
 appveyor.yml | 10 ++++------
 2 files changed, 8 insertions(+), 12 deletions(-)

diff --git a/.travis.yml b/.travis.yml
index 1b0d775..fb53d45 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -16,8 +16,9 @@ branches:
     - develop
 
 install:
-  - git clone -b $TRAVIS_BRANCH https://github.com/boostorg/boost.git boost
-  - cd boost
+  - cd ..
+  - git clone -b $TRAVIS_BRANCH https://github.com/boostorg/boost.git boost-root
+  - cd boost-root
   - git submodule init libs/align
   - git submodule init libs/assert
   - git submodule init libs/atomic
@@ -29,16 +30,13 @@ install:
   - git submodule init libs/move
   - git submodule init libs/predef
   - git submodule init libs/preprocessor
-  - git submodule init libs/smart_ptr
   - git submodule init libs/static_assert
   - git submodule init libs/throw_exception
   - git submodule init libs/type_traits
   - git submodule init tools/build
   - git submodule init tools/inspect
   - git submodule update
-  - cd libs/smart_ptr
-  - git checkout -q $TRAVIS_COMMIT
-  - cd ../..
+  - cp -r $TRAVIS_BUILD_DIR/* libs/smart_ptr
   - ./bootstrap.sh
   - ./b2 headers
 
diff --git a/appveyor.yml b/appveyor.yml
index 8132b0d..d35c12d 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -12,8 +12,9 @@ branches:
     - develop
 
 install:
-  - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost
-  - cd boost
+  - cd ..
+  - git clone -b %APPVEYOR_REPO_BRANCH% https://github.com/boostorg/boost.git boost-root
+  - cd boost-root
   - git submodule init libs/align
   - git submodule init libs/assert
   - git submodule init libs/atomic
@@ -25,16 +26,13 @@ install:
   - git submodule init libs/move
   - git submodule init libs/predef
   - git submodule init libs/preprocessor
-  - git submodule init libs/smart_ptr
   - git submodule init libs/static_assert
   - git submodule init libs/throw_exception
   - git submodule init libs/type_traits
   - git submodule init tools/build
   - git submodule init tools/inspect
   - git submodule update
-  - cd libs\smart_ptr
-  - git checkout -q %APPVEYOR_REPO_COMMIT%
-  - cd ..\..
+  - xcopy /s /e /q %APPVEYOR_BUILD_FOLDER% libs\smart_ptr
   - bootstrap
   - b2 headers
 

From 190c06e25d026f68696bd7e16443f7e82e24814c Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 17:55:14 +0300
Subject: [PATCH 12/18] Add tests for unique_ptr casts.

---
 include/boost/pointer_cast.hpp |  17 ++-
 test/Jamfile.v2                |   3 +
 test/pointer_cast_test2.cpp    | 214 +++++++++++++++++++++++++++++++++
 test/pointer_cast_test3.cpp    |  49 ++++++++
 4 files changed, 278 insertions(+), 5 deletions(-)
 create mode 100644 test/pointer_cast_test2.cpp
 create mode 100644 test/pointer_cast_test3.cpp

diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp
index 6a5af8b..e5cd41f 100644
--- a/include/boost/pointer_cast.hpp
+++ b/include/boost/pointer_cast.hpp
@@ -7,11 +7,11 @@
 //
 //////////////////////////////////////////////////////////////////////////////
 
-#include 
-
 #ifndef BOOST_POINTER_CAST_HPP
 #define BOOST_POINTER_CAST_HPP
 
+#include 
+
 namespace boost { 
 
 //static_pointer_cast overload for raw pointers
@@ -90,8 +90,11 @@ template std::shared_ptr reinterpret_pointer_cast(const std
 //static_pointer_cast overload for std::unique_ptr
 template std::unique_ptr static_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
+   typedef typename std::unique_ptr::element_type E;
+
    detail::assert_safe_moving_upcast();
-   return std::unique_ptr( static_cast( r.release() ) );
+
+   return std::unique_ptr( static_cast( r.release() ) );
 }
 
 //dynamic_pointer_cast overload for std::unique_ptr
@@ -107,13 +110,17 @@ template std::unique_ptr dynamic_pointer_cast( std::unique_
 //const_pointer_cast overload for std::unique_ptr
 template std::unique_ptr const_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   return std::unique_ptr( const_cast( r.release() ) );
+   typedef typename std::unique_ptr::element_type E;
+
+   return std::unique_ptr( const_cast( r.release() ) );
 }
 
 //reinterpret_pointer_cast overload for std::unique_ptr
 template std::unique_ptr reinterpret_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   return std::unique_ptr( reinterpret_cast( r.release() ) );
+   typedef typename std::unique_ptr::element_type E;
+
+   return std::unique_ptr( reinterpret_cast( r.release() ) );
 }
 
 } // namespace boost
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 6eb4c89..596e167 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -186,5 +186,8 @@ import testing ;
 
           [ run sp_hash_test2.cpp ]
           [ run sp_hash_test3.cpp ]
+
+          [ run pointer_cast_test2.cpp ]
+          [ run pointer_cast_test3.cpp ]
         ;
 }
diff --git a/test/pointer_cast_test2.cpp b/test/pointer_cast_test2.cpp
new file mode 100644
index 0000000..a74058b
--- /dev/null
+++ b/test/pointer_cast_test2.cpp
@@ -0,0 +1,214 @@
+//
+//  pointer_cast_test2.cpp - a test for unique_ptr casts
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+
+#if defined( BOOST_NO_CXX11_SMART_PTR )
+
+int main()
+{
+    return 0;
+}
+
+#else
+
+#include 
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+struct D: B
+{
+};
+
+static void test_static_cast()
+{
+    {
+        std::unique_ptr p1( new int );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int[ 1 ] );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int[ 1 ] );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new D );
+        D * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new D );
+        B * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+}
+
+static void test_const_cast()
+{
+    {
+        std::unique_ptr p1( new int );
+        int const * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int[ 1 ] );
+        int * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+}
+
+static void test_dynamic_cast()
+{
+    {
+        std::unique_ptr p1( new D );
+        D * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new D );
+        B * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+}
+
+static void test_reinterpret_cast()
+{
+    {
+        std::unique_ptr p1( new int );
+        void * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+
+        p1 = boost::reinterpret_pointer_cast( std::move( p2 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p1.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int );
+        void * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+
+        p1 = boost::reinterpret_pointer_cast( std::move( p2 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p1.get(), q1 );
+    }
+
+    {
+        std::unique_ptr p1( new int[ 1 ] );
+        void * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::reinterpret_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+
+        p1 = boost::reinterpret_pointer_cast( std::move( p2 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p1.get(), q1 );
+    }
+}
+
+int main()
+{
+    test_static_cast();
+    test_const_cast();
+    test_dynamic_cast();
+    test_reinterpret_cast();
+
+    return boost::report_errors();
+}
+
+#endif
diff --git a/test/pointer_cast_test3.cpp b/test/pointer_cast_test3.cpp
new file mode 100644
index 0000000..c2b19f9
--- /dev/null
+++ b/test/pointer_cast_test3.cpp
@@ -0,0 +1,49 @@
+//
+//  pointer_cast_test3.cpp - a test for unique_ptr casts
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+
+#if defined( BOOST_NO_CXX11_SMART_PTR )
+
+int main()
+{
+    return 0;
+}
+
+#else
+
+#include 
+#include 
+#include 
+
+// This test fails on msvc-10.0, 11.0, 12.0 because
+// their unique_ptr implementation can't compile the
+// initialization of p1
+
+static void test_const_cast()
+{
+    {
+        std::unique_ptr p1( new int[ 1 ] );
+        int const * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+}
+
+int main()
+{
+    test_const_cast();
+    return boost::report_errors();
+}
+
+#endif

From a14515a3646cffc905915776f502ba7dd2d8c4c0 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 18:43:22 +0300
Subject: [PATCH 13/18] Add negative pointer cast tests.

---
 include/boost/pointer_cast.hpp | 38 ++++++++++++++++++++--------------
 test/Jamfile.v2                | 12 +++++++++++
 test/pointer_cast_co_fail.cpp  | 18 ++++++++++++++++
 test/pointer_cast_co_fail2.cpp | 18 ++++++++++++++++
 test/pointer_cast_co_fail3.cpp | 29 ++++++++++++++++++++++++++
 test/pointer_cast_dy_fail.cpp  | 25 ++++++++++++++++++++++
 test/pointer_cast_dy_fail2.cpp | 25 ++++++++++++++++++++++
 test/pointer_cast_dy_fail3.cpp | 29 ++++++++++++++++++++++++++
 test/pointer_cast_st_fail.cpp  | 18 ++++++++++++++++
 test/pointer_cast_st_fail2.cpp | 18 ++++++++++++++++
 test/pointer_cast_st_fail3.cpp | 29 ++++++++++++++++++++++++++
 11 files changed, 244 insertions(+), 15 deletions(-)
 create mode 100644 test/pointer_cast_co_fail.cpp
 create mode 100644 test/pointer_cast_co_fail2.cpp
 create mode 100644 test/pointer_cast_co_fail3.cpp
 create mode 100644 test/pointer_cast_dy_fail.cpp
 create mode 100644 test/pointer_cast_dy_fail2.cpp
 create mode 100644 test/pointer_cast_dy_fail3.cpp
 create mode 100644 test/pointer_cast_st_fail.cpp
 create mode 100644 test/pointer_cast_st_fail2.cpp
 create mode 100644 test/pointer_cast_st_fail3.cpp

diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp
index e5cd41f..44e67e4 100644
--- a/include/boost/pointer_cast.hpp
+++ b/include/boost/pointer_cast.hpp
@@ -79,48 +79,56 @@ using std::const_pointer_cast;
 //reinterpret_pointer_cast overload for std::shared_ptr
 template std::shared_ptr reinterpret_pointer_cast(const std::shared_ptr & r ) BOOST_NOEXCEPT
 {
-   (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) );
+    (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) );
 
-   typedef typename std::shared_ptr::element_type E;
+    typedef typename std::shared_ptr::element_type E;
 
-   E * p = reinterpret_cast< E* >( r.get() );
-   return std::shared_ptr( r, p );
+    E * p = reinterpret_cast< E* >( r.get() );
+    return std::shared_ptr( r, p );
 }
 
 //static_pointer_cast overload for std::unique_ptr
 template std::unique_ptr static_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   typedef typename std::unique_ptr::element_type E;
+    (void) static_cast< T* >( static_cast< U* >( 0 ) );
 
-   detail::assert_safe_moving_upcast();
+    typedef typename std::unique_ptr::element_type E;
 
-   return std::unique_ptr( static_cast( r.release() ) );
+    detail::assert_safe_moving_upcast();
+
+    return std::unique_ptr( static_cast( r.release() ) );
 }
 
 //dynamic_pointer_cast overload for std::unique_ptr
 template std::unique_ptr dynamic_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   detail::assert_safe_moving_upcast();
+    (void) dynamic_cast< T* >( static_cast< U* >( 0 ) );
 
-   T * p = dynamic_cast( r.get() );
-   if( p ) r.release();
-   return std::unique_ptr( p );
+    detail::assert_safe_moving_upcast();
+
+    T * p = dynamic_cast( r.get() );
+    if( p ) r.release();
+    return std::unique_ptr( p );
 }
 
 //const_pointer_cast overload for std::unique_ptr
 template std::unique_ptr const_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   typedef typename std::unique_ptr::element_type E;
+    (void) const_cast< T* >( static_cast< U* >( 0 ) );
 
-   return std::unique_ptr( const_cast( r.release() ) );
+    typedef typename std::unique_ptr::element_type E;
+
+    return std::unique_ptr( const_cast( r.release() ) );
 }
 
 //reinterpret_pointer_cast overload for std::unique_ptr
 template std::unique_ptr reinterpret_pointer_cast( std::unique_ptr && r ) BOOST_NOEXCEPT
 {
-   typedef typename std::unique_ptr::element_type E;
+    (void) reinterpret_cast< T* >( static_cast< U* >( 0 ) );
 
-   return std::unique_ptr( reinterpret_cast( r.release() ) );
+    typedef typename std::unique_ptr::element_type E;
+
+    return std::unique_ptr( reinterpret_cast( r.release() ) );
 }
 
 } // namespace boost
diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index 596e167..bf38dae 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -189,5 +189,17 @@ import testing ;
 
           [ run pointer_cast_test2.cpp ]
           [ run pointer_cast_test3.cpp ]
+
+          [ compile-fail pointer_cast_st_fail.cpp ]
+          [ compile-fail pointer_cast_st_fail2.cpp ]
+          [ compile-fail pointer_cast_st_fail3.cpp ]
+
+          [ compile-fail pointer_cast_co_fail.cpp ]
+          [ compile-fail pointer_cast_co_fail2.cpp ]
+          [ compile-fail pointer_cast_co_fail3.cpp ]
+
+          [ compile-fail pointer_cast_dy_fail.cpp ]
+          [ compile-fail pointer_cast_dy_fail2.cpp ]
+          [ compile-fail pointer_cast_dy_fail3.cpp ]
         ;
 }
diff --git a/test/pointer_cast_co_fail.cpp b/test/pointer_cast_co_fail.cpp
new file mode 100644
index 0000000..d8960b2
--- /dev/null
+++ b/test/pointer_cast_co_fail.cpp
@@ -0,0 +1,18 @@
+//
+//  A negative test for unique_ptr const_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+int main()
+{
+    std::unique_ptr p1( new int );
+    std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_co_fail2.cpp b/test/pointer_cast_co_fail2.cpp
new file mode 100644
index 0000000..7fa8e18
--- /dev/null
+++ b/test/pointer_cast_co_fail2.cpp
@@ -0,0 +1,18 @@
+//
+//  A negative test for unique_ptr const_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+int main()
+{
+    std::unique_ptr p1( new int[ 1 ] );
+    std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_co_fail3.cpp b/test/pointer_cast_co_fail3.cpp
new file mode 100644
index 0000000..d8872c8
--- /dev/null
+++ b/test/pointer_cast_co_fail3.cpp
@@ -0,0 +1,29 @@
+//
+//  A negative test for unique_ptr const_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+struct D: B
+{
+};
+
+int main()
+{
+    std::unique_ptr p1( new D[ 1 ] );
+    std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_dy_fail.cpp b/test/pointer_cast_dy_fail.cpp
new file mode 100644
index 0000000..c6df69d
--- /dev/null
+++ b/test/pointer_cast_dy_fail.cpp
@@ -0,0 +1,25 @@
+//
+//  A negative test for unique_ptr dynamic_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+int main()
+{
+    std::unique_ptr p1( new B );
+    std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_dy_fail2.cpp b/test/pointer_cast_dy_fail2.cpp
new file mode 100644
index 0000000..223977a
--- /dev/null
+++ b/test/pointer_cast_dy_fail2.cpp
@@ -0,0 +1,25 @@
+//
+//  A negative test for unique_ptr dynamic_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+int main()
+{
+    std::unique_ptr p1( new B[ 1 ] );
+    std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_dy_fail3.cpp b/test/pointer_cast_dy_fail3.cpp
new file mode 100644
index 0000000..1ac52e7
--- /dev/null
+++ b/test/pointer_cast_dy_fail3.cpp
@@ -0,0 +1,29 @@
+//
+//  A negative test for unique_ptr dynamic_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+struct D: B
+{
+};
+
+int main()
+{
+    std::unique_ptr p1( new D[ 1 ] );
+    std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_st_fail.cpp b/test/pointer_cast_st_fail.cpp
new file mode 100644
index 0000000..0fcf8c1
--- /dev/null
+++ b/test/pointer_cast_st_fail.cpp
@@ -0,0 +1,18 @@
+//
+//  A negative test for unique_ptr static_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+int main()
+{
+    std::unique_ptr p1( new int );
+    std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_st_fail2.cpp b/test/pointer_cast_st_fail2.cpp
new file mode 100644
index 0000000..3b227b9
--- /dev/null
+++ b/test/pointer_cast_st_fail2.cpp
@@ -0,0 +1,18 @@
+//
+//  A negative test for unique_ptr static_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+int main()
+{
+    std::unique_ptr p1( new int[ 1 ] );
+    std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+}
diff --git a/test/pointer_cast_st_fail3.cpp b/test/pointer_cast_st_fail3.cpp
new file mode 100644
index 0000000..4ca6a89
--- /dev/null
+++ b/test/pointer_cast_st_fail3.cpp
@@ -0,0 +1,29 @@
+//
+//  A negative test for unique_ptr static_cast
+//
+//  Copyright 2016 Peter Dimov
+//
+//  Distributed under the Boost Software License, Version 1.0.
+//  See accompanying file LICENSE_1_0.txt or copy at
+//  http://www.boost.org/LICENSE_1_0.txt
+//
+
+#include 
+#include 
+
+struct B
+{
+    virtual ~B()
+    {
+    }
+};
+
+struct D: B
+{
+};
+
+int main()
+{
+    std::unique_ptr p1( new D[ 1 ] );
+    std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+}

From 8fac3c9f2f78665afc3b893a7f657d779e8ea97f Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 19:15:47 +0300
Subject: [PATCH 14/18] Add one more dynamic_cast test, fold back _test3 into
 test2.

---
 test/Jamfile.v2             |  1 -
 test/pointer_cast_test2.cpp | 24 ++++++++++++++++++
 test/pointer_cast_test3.cpp | 49 -------------------------------------
 3 files changed, 24 insertions(+), 50 deletions(-)
 delete mode 100644 test/pointer_cast_test3.cpp

diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index bf38dae..bb4d04e 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -188,7 +188,6 @@ import testing ;
           [ run sp_hash_test3.cpp ]
 
           [ run pointer_cast_test2.cpp ]
-          [ run pointer_cast_test3.cpp ]
 
           [ compile-fail pointer_cast_st_fail.cpp ]
           [ compile-fail pointer_cast_st_fail2.cpp ]
diff --git a/test/pointer_cast_test2.cpp b/test/pointer_cast_test2.cpp
index a74058b..279c4ab 100644
--- a/test/pointer_cast_test2.cpp
+++ b/test/pointer_cast_test2.cpp
@@ -119,7 +119,21 @@ static void test_const_cast()
         BOOST_TEST_EQ( p2.get(), q1 );
     }
 
+#if !defined( BOOST_MSVC ) || BOOST_MSVC >= 1900
+
     {
+        std::unique_ptr p1( new int[ 1 ] );
+        int const * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
+
+#endif
+
+	{
         std::unique_ptr p1( new int[ 1 ] );
         int * q1 = p1.get();
 
@@ -151,6 +165,16 @@ static void test_dynamic_cast()
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
     }
+
+    {
+        std::unique_ptr p1( new B );
+        B * q1 = p1.get();
+
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p1.get(), q1 );
+    }
 }
 
 static void test_reinterpret_cast()
diff --git a/test/pointer_cast_test3.cpp b/test/pointer_cast_test3.cpp
deleted file mode 100644
index c2b19f9..0000000
--- a/test/pointer_cast_test3.cpp
+++ /dev/null
@@ -1,49 +0,0 @@
-//
-//  pointer_cast_test3.cpp - a test for unique_ptr casts
-//
-//  Copyright 2016 Peter Dimov
-//
-//  Distributed under the Boost Software License, Version 1.0.
-//  See accompanying file LICENSE_1_0.txt or copy at
-//  http://www.boost.org/LICENSE_1_0.txt
-//
-
-#include 
-
-#if defined( BOOST_NO_CXX11_SMART_PTR )
-
-int main()
-{
-    return 0;
-}
-
-#else
-
-#include 
-#include 
-#include 
-
-// This test fails on msvc-10.0, 11.0, 12.0 because
-// their unique_ptr implementation can't compile the
-// initialization of p1
-
-static void test_const_cast()
-{
-    {
-        std::unique_ptr p1( new int[ 1 ] );
-        int const * q1 = p1.get();
-
-        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
-
-        BOOST_TEST( p1.get() == 0 );
-        BOOST_TEST_EQ( p2.get(), q1 );
-    }
-}
-
-int main()
-{
-    test_const_cast();
-    return boost::report_errors();
-}
-
-#endif

From b5498d944e4eb14d90dc74b0edb13a09f9e0eab2 Mon Sep 17 00:00:00 2001
From: Giel van Schijndel 
Date: Sat, 10 Sep 2016 16:14:16 +0200
Subject: [PATCH 15/18] Add test for make_shared's move-emulation support

This tests the functionality added with PR boostorg/smart_ptr#24.

Specifically this tests that passing moveable-only types to
constructors is possible through make_shared. Note that real rvalue's
still cannot be passed that way on C++03 unfortunately because there's
no generic way of accomplishing that with current move emulation.
---
 test/Jamfile.v2                          |  1 +
 test/make_shared_move_emulation_test.cpp | 81 ++++++++++++++++++++++++
 2 files changed, 82 insertions(+)
 create mode 100644 test/make_shared_move_emulation_test.cpp

diff --git a/test/Jamfile.v2 b/test/Jamfile.v2
index d965bfd..11c41c2 100644
--- a/test/Jamfile.v2
+++ b/test/Jamfile.v2
@@ -47,6 +47,7 @@ import testing ;
           [ run spinlock_try_test.cpp : : : multi : spinlock_try_test.mt ]
           [ run spinlock_pool_test.cpp ]
           [ run make_shared_test.cpp ]
+          [ run make_shared_move_emulation_test.cpp ]
           [ run make_shared_perfect_forwarding_test.cpp ]
           [ run shared_ptr_convertible_test.cpp ]
           [ run wp_convertible_test.cpp ]
diff --git a/test/make_shared_move_emulation_test.cpp b/test/make_shared_move_emulation_test.cpp
new file mode 100644
index 0000000..c607e05
--- /dev/null
+++ b/test/make_shared_move_emulation_test.cpp
@@ -0,0 +1,81 @@
+// make_shared_move_emulation_test.cpp - a test of make_shared
+//   semi-perfect forwarding of constructor arguments when using a C++03
+//   compiler with move emulation.
+//   Note the "semi": it means moving temporaries (real r-values) doesn't work.
+//
+// Copyright 2016 Giel van Schijndel
+//
+// Distributed under the Boost Software License, Version 1.0.
+// See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+class movearg
+{
+private:
+    BOOST_MOVABLE_BUT_NOT_COPYABLE(movearg)
+public:
+    movearg()
+    {}
+    movearg(BOOST_RV_REF(movearg))
+    {}
+    movearg& operator=(BOOST_RV_REF(movearg))
+    {
+        return *this;
+    }
+};
+
+class ByVal
+{
+public:
+    ByVal(movearg) {}
+};
+
+class ByRef
+{
+public:
+    enum constructor_id
+    {
+        move_constructor,
+        const_ref_constructor
+    };
+
+    ByRef(BOOST_RV_REF(movearg)): constructed_by_(move_constructor)
+    {}
+    ByRef(const movearg &arg): constructed_by_(const_ref_constructor)
+    {}
+
+    constructor_id constructed_by_;
+};
+
+int main()
+{
+    {
+        movearg a;
+        boost::shared_ptr< ByVal > x = boost::make_shared< ByVal >(boost::move(a));
+    }
+    {
+        movearg a;
+        boost::shared_ptr< ByRef > x = boost::make_shared< ByRef >(boost::move(a));
+        BOOST_TEST( x->constructed_by_ == ByRef::move_constructor);
+    }
+#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
+    {
+        boost::shared_ptr< ByVal > x = boost::make_shared< ByVal >(movearg());
+        boost::shared_ptr< ByRef > y = boost::make_shared< ByRef >(movearg());
+        BOOST_TEST( y->constructed_by_ == ByRef::move_constructor);
+    }
+#endif // !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
+    {
+        const movearg ca;
+        boost::shared_ptr< ByRef > x = boost::make_shared< ByRef >(ca);
+        BOOST_TEST( x->constructed_by_ == ByRef::const_ref_constructor);
+    }
+
+    return boost::report_errors();
+}

From 2ae3e4ba4479f8fbd2d4184b89d5e386fa5cb650 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 20:07:47 +0300
Subject: [PATCH 16/18] Remove static_pointer_cast restriction; test dynamic
 cross cast.

---
 include/boost/pointer_cast.hpp |  2 -
 test/pointer_cast_test2.cpp    | 75 ++++++++++++++++++++++------------
 2 files changed, 49 insertions(+), 28 deletions(-)

diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp
index 44e67e4..7e04512 100644
--- a/include/boost/pointer_cast.hpp
+++ b/include/boost/pointer_cast.hpp
@@ -94,8 +94,6 @@ template std::unique_ptr static_pointer_cast( std::unique_p
 
     typedef typename std::unique_ptr::element_type E;
 
-    detail::assert_safe_moving_upcast();
-
     return std::unique_ptr( static_cast( r.release() ) );
 }
 
diff --git a/test/pointer_cast_test2.cpp b/test/pointer_cast_test2.cpp
index 279c4ab..b8575b4 100644
--- a/test/pointer_cast_test2.cpp
+++ b/test/pointer_cast_test2.cpp
@@ -23,15 +23,15 @@ int main()
 #include 
 #include 
 
-struct B
+struct B1
 {
-    virtual ~B()
-    {
-    }
 };
 
-struct D: B
+struct D1: B1
 {
+    ~D1()
+    {
+    }
 };
 
 static void test_static_cast()
@@ -77,23 +77,18 @@ static void test_static_cast()
     }
 
     {
-        std::unique_ptr p1( new D );
-        D * q1 = p1.get();
+        std::unique_ptr p1( new D1 );
+        D1 * q1 = p1.get();
 
-        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
+        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
 
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
-    }
 
-    {
-        std::unique_ptr p1( new D );
-        B * q1 = p1.get();
+        std::unique_ptr p3 = boost::static_pointer_cast( std::move( p2 ) );
 
-        std::unique_ptr p2 = boost::static_pointer_cast( std::move( p1 ) );
-
-        BOOST_TEST( p1.get() == 0 );
-        BOOST_TEST_EQ( p2.get(), q1 );
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p3.get(), q1 );
     }
 }
 
@@ -133,7 +128,7 @@ static void test_const_cast()
 
 #endif
 
-	{
+    {
         std::unique_ptr p1( new int[ 1 ] );
         int * q1 = p1.get();
 
@@ -144,37 +139,65 @@ static void test_const_cast()
     }
 }
 
+struct B2
+{
+    virtual ~B2()
+    {
+    }
+};
+
+struct C2
+{
+    virtual ~C2()
+    {
+    }
+};
+
+struct D2: B2, C2
+{
+};
+
 static void test_dynamic_cast()
 {
     {
-        std::unique_ptr p1( new D );
-        D * q1 = p1.get();
+        std::unique_ptr p1( new D2 );
+        D2 * q1 = p1.get();
 
-        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
 
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
     }
 
     {
-        std::unique_ptr p1( new D );
-        B * q1 = p1.get();
+        std::unique_ptr p1( new D2 );
+        B2 * q1 = p1.get();
 
-        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
 
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
     }
 
     {
-        std::unique_ptr p1( new B );
-        B * q1 = p1.get();
+        std::unique_ptr p1( new B2 );
+        B2 * q1 = p1.get();
 
-        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
 
         BOOST_TEST( p2.get() == 0 );
         BOOST_TEST_EQ( p1.get(), q1 );
     }
+
+    {
+        D2 * q1 = new D2;
+        std::unique_ptr p1( q1 );
+
+        std::unique_ptr p2 = boost::dynamic_pointer_cast( std::move( p1 ) );
+
+        BOOST_TEST( p1.get() == 0 );
+        BOOST_TEST_EQ( p2.get(), q1 );
+    }
 }
 
 static void test_reinterpret_cast()

From 5595622c3eb401dd4d8aa5fab8e888f7edf873d5 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 20:18:37 +0300
Subject: [PATCH 17/18] Relax dynamic_cast check; rephrase const_cast test to
 be more MSVC-friendly.

---
 include/boost/pointer_cast.hpp | 19 ++----------------
 test/pointer_cast_test2.cpp    | 36 +++++++++++-----------------------
 2 files changed, 13 insertions(+), 42 deletions(-)

diff --git a/include/boost/pointer_cast.hpp b/include/boost/pointer_cast.hpp
index 7e04512..5af4971 100644
--- a/include/boost/pointer_cast.hpp
+++ b/include/boost/pointer_cast.hpp
@@ -46,27 +46,12 @@ inline T* reinterpret_pointer_cast(U *ptr)
 
 #if !defined( BOOST_NO_CXX11_SMART_PTR )
 
-#include 
-
-#include 
-#include 
 #include 
-
+#include 
 #include 
 
 namespace boost {
 
-namespace detail {
-
-template
-void assert_safe_moving_upcast() {
-   BOOST_STATIC_ASSERT_MSG( !(boost::is_base_of::value && !boost::is_pod::value && !boost::has_virtual_destructor::value)
-     , "Upcast from a non-POD child to a base without virtual destructor is unsafe, because the child's destructor "
-       "will not be called when the base pointer is deleted. Consider using shared_ptr for such types.");
-}
-
-}
-
 //static_pointer_cast overload for std::shared_ptr
 using std::static_pointer_cast;
 
@@ -102,7 +87,7 @@ template std::unique_ptr dynamic_pointer_cast( std::unique_
 {
     (void) dynamic_cast< T* >( static_cast< U* >( 0 ) );
 
-    detail::assert_safe_moving_upcast();
+    BOOST_STATIC_ASSERT_MSG( boost::has_virtual_destructor::value, "The target of dynamic_pointer_cast must have a virtual destructor." );
 
     T * p = dynamic_cast( r.get() );
     if( p ) r.release();
diff --git a/test/pointer_cast_test2.cpp b/test/pointer_cast_test2.cpp
index b8575b4..eb28a5d 100644
--- a/test/pointer_cast_test2.cpp
+++ b/test/pointer_cast_test2.cpp
@@ -94,16 +94,6 @@ static void test_static_cast()
 
 static void test_const_cast()
 {
-    {
-        std::unique_ptr p1( new int );
-        int const * q1 = p1.get();
-
-        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
-
-        BOOST_TEST( p1.get() == 0 );
-        BOOST_TEST_EQ( p2.get(), q1 );
-    }
-
     {
         std::unique_ptr p1( new int );
         int * q1 = p1.get();
@@ -112,22 +102,13 @@ static void test_const_cast()
 
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
+
+        std::unique_ptr p3 = boost::const_pointer_cast( std::move( p2 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p3.get(), q1 );
     }
 
-#if !defined( BOOST_MSVC ) || BOOST_MSVC >= 1900
-
-    {
-        std::unique_ptr p1( new int[ 1 ] );
-        int const * q1 = p1.get();
-
-        std::unique_ptr p2 = boost::const_pointer_cast( std::move( p1 ) );
-
-        BOOST_TEST( p1.get() == 0 );
-        BOOST_TEST_EQ( p2.get(), q1 );
-    }
-
-#endif
-
     {
         std::unique_ptr p1( new int[ 1 ] );
         int * q1 = p1.get();
@@ -136,7 +117,12 @@ static void test_const_cast()
 
         BOOST_TEST( p1.get() == 0 );
         BOOST_TEST_EQ( p2.get(), q1 );
-    }
+
+        std::unique_ptr p3 = boost::const_pointer_cast( std::move( p2 ) );
+
+        BOOST_TEST( p2.get() == 0 );
+        BOOST_TEST_EQ( p3.get(), q1 );
+	}
 }
 
 struct B2

From 3aa720714d76b57fd758e2507bd0c0d1105e60b4 Mon Sep 17 00:00:00 2001
From: Peter Dimov 
Date: Sat, 10 Sep 2016 20:57:35 +0300
Subject: [PATCH 18/18] Update documentation.

---
 pointer_cast.html | 168 ++++++++++++++++++++++++----------------------
 1 file changed, 87 insertions(+), 81 deletions(-)

diff --git a/pointer_cast.html b/pointer_cast.html
index f0c7fa2..bf63043 100644
--- a/pointer_cast.html
+++ b/pointer_cast.html
@@ -2,16 +2,16 @@
 
     
         pointer_cast
-        
+        
     
     
         

boost.png (6897 bytes)pointer_cast

+ width="277" align="middle" border="0" />pointer_cast

The pointer cast functions (boost::static_pointer_cast boost::dynamic_pointer_cast boost::reinterpret_pointer_cast boost::const_pointer_cast) - provide a way to write generic pointer castings for raw pointers, std::shared_ptr and std::unique_ptr. The functions - are defined in boost/pointer_cast.hpp.

-

There is test/example code in pointer_cast_test.cpp.

+ provide a way to write generic pointer castings for raw pointers, std::shared_ptr and std::unique_ptr. The functions + are defined in boost/pointer_cast.hpp.

+

There is test/example code in pointer_cast_test.cpp.

Rationale

Boost smart pointers usually overload those functions to provide a mechanism to emulate pointers casts. For example, boost::shared_ptr<...> implements @@ -20,15 +20,15 @@ template<class T, class U> shared_ptr<T> static_pointer_cast(shared_ptr<U> const &r);

-

Pointer cast functions from boost/pointer_cast.hpp +

Pointer cast functions from boost/pointer_cast.hpp are overloads of boost::static_pointer_cast, boost::dynamic_pointer_cast, boost::reinterpret_pointer_cast and boost::const_pointer_cast - for raw pointers, std::shared_ptr and std::unique_ptr. This way when developing pointer type independent classes, - for example, memory managers or shared memory compatible classes, the same code - can be used for raw and smart pointers.

-

Synopsis

-
-
+            for raw pointers, std::shared_ptr and std::unique_ptr. This way when developing
+            pointer type independent classes, for example, memory managers or shared memory compatible classes, the same
+            code can be used for raw and smart pointers.

+

Synopsis

+
+
 namespace boost {
 
 template<class T, class U>
@@ -48,84 +48,91 @@ inline T* reinterpret_pointer_cast(U *ptr)
   { return reinterpret_cast<T*>(ptr); }
 
 template<class T, class U>
-inline std::shared_ptr<U> static_pointer_cast(std::shared_ptr<T> ptr);
+inline std::shared_ptr<T> static_pointer_cast(std::shared_ptr<U> const& r);
 
 template<class T, class U>
-inline std::shared_ptr<U> dynamic_pointer_cast(std::shared_ptr<T> ptr);
+inline std::shared_ptr<T> dynamic_pointer_cast(std::shared_ptr<U> const& r);
 
 template<class T, class U>
-inline std::shared_ptr<U> const_pointer_cast(std::shared_ptr<T> ptr);
+inline std::shared_ptr<T> const_pointer_cast(std::shared_ptr<U> const& r);
 
 template<class T, class U>
-inline std::shared_ptr<U> reinterpret_pointer_cast(std::shared_ptr<T> ptr);
+inline std::shared_ptr<T> reinterpret_pointer_cast(std::shared_ptr<U> const& r);
 
 template<class T, class U>
-inline std::unique_ptr<U> static_pointer_cast(std::unique_ptr<T> &&ptr);
+inline std::unique_ptr<T> static_pointer_cast(std::unique_ptr<U>&& r);
 
 template<class T, class U>
-inline std::unique_ptr<U> dynamic_pointer_cast(std::unique_ptr<T> &&ptr);
+inline std::unique_ptr<T> dynamic_pointer_cast(std::unique_ptr<U>&& r);
 
 template<class T, class U>
-inline std::unique_ptr<U> const_pointer_cast(std::unique_ptr<T> &&ptr);
+inline std::unique_ptr<T> const_pointer_cast(std::unique_ptr<U>&& r);
 
 template<class T, class U>
-inline std::unique_ptr<U> reinterpret_pointer_cast(std::unique_ptr<T> &&ptr);
+inline std::unique_ptr<T> reinterpret_pointer_cast(std::unique_ptr<U>&& r);
   
 } // namespace boost
-
-
-

As you can see from the above synopsis, the pointer cast functions for raw pointers are just - wrappers around standard C++ cast operators.

+
+
+

As you can see from the above synopsis, the pointer cast functions for raw pointers are just + wrappers around standard C++ cast operators.

-

Memory Safety

-

It is possible to write unsafe code, when upcasting to a base type without virtual destructor. - Consider the following example:

-
-#include <memory>
-#include <utility>
-#include <boost/pointer_cast.hpp>
-#include <boost/make_unique.hpp>
+        

The pointer casts for std::shared_ptr are aliases of the corresponding standard + functions with the same names and equivalent to the + functions taking boost::shared_ptr.

-int destructed = 0; +

The pointer casts for std::unique_ptr are documented below.

-struct base { - ~base() { - // ... - } -}; +

static_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> static_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression static_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( static_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+

Notes: the seemingly equivalent expression + unique_ptr<T>(static_cast<T*>(r.get())) + will eventually result in undefined behavior, attempting to delete the same + object twice.

+
+

const_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> const_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression const_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( const_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+
+

dynamic_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> dynamic_pointer_cast(unique_ptr<U>&& r);
+
+

Requires: The expression dynamic_cast<T*>( (U*)0 ) + must be well-formed. T must have a virtual destructor.

+

Returns:

+
    +
  • + When dynamic_cast<typename unique_ptr<T>::element_type*>(r.get()) returns a nonzero value, + unique_ptr<T>(dynamic_cast<typename unique_ptr<T>::element_type*>(r.release()));
  • +
  • + Otherwise, unique_ptr<T>().
+

Throws: nothing.

+
+

reinterpret_pointer_cast

+
template<class T, class U>
+  unique_ptr<T> reinterpret_pointer_cast(unique_ptr<U>&& r); // never throws
+
+

Requires: The expression reinterpret_cast<T*>( (U*)0 ) + must be well-formed.

+

Returns: unique_ptr<T>( reinterpret_cast<typename unique_ptr<T>::element_type*>(r.release()) ).

+

Throws: nothing.

+
-struct child : base { - virtual ~child() { - destructed++; - } -} - -int main() { - { - std::unique_ptr tmp = boost::make_unique(); - std::unique_ptr sink = boost::static_pointer_cast( std::move(tmp) ); - } - - // child::~child was never called - assert(destructed == 0); - - return 0; -} -
-

In this example, the child destructor child::~child was never called, because the child* in tmp - was downcast to a base* and moved into sink. The destructor of tmp did essentially nothing, because - it contained nullptr during destruction; sink deleted the pointer, but since base::~base is non-virtual - the child destructor was never called.

-

boost::static_pointer_cast and boost::dynamic_pointer_cast for std::unique_ptr prevent the above scenario - by raising a compiler error when such a cast is detected.

-

The overloads for std::shared_ptr and boost::shared_ptr are not prone to this problem, since they internally - always store the original pointer with the original type.

-

The plain pointer casts are in principle also prone to that problem, but it is assumed that raw pointers - are non-owning, so no checking is performed.

- -

Example

-
-
+        

Example

+
+
 #include <boost/pointer_cast.hpp>
 #include <boost/shared_ptr.hpp>
 
@@ -150,28 +157,27 @@ void check_if_it_is_derived(const BasePtr &ptr)
 
 int main()
 {
-   // Create a raw and a shared_ptr
+   // Create a raw and a shared_ptr
 
    base *ptr = new derived;
    boost::shared_ptr<base> sptr(new derived);
    
-   // Check that base pointer points actually to derived class
+   // Check that base pointer points actually to derived class
 
    check_if_it_is_derived(ptr);
    check_if_it_is_derived(sptr);
    
-   // Ok!
+   // Ok!
    
    delete ptr;
    return 0;
-}
-
-

The example demonstrates how the generic pointer casts help us create pointer - independent code.

-
-

$Date$

+}
+
+

The example demonstrates how the generic pointer casts help us create pointer + independent code.

+

Copyright 2005 Ion Gaztaņaga. Use, modification, and distribution are subject to - the Boost Software License, Version 1.0. (See accompanying file - LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)

+ the Boost Software License, Version 1.0. (See accompanying file + LICENSE_1_0.txt or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)