Compare commits

...

20 Commits

Author SHA1 Message Date
Peter Dimov
b6b49ef591 Split g++ 8 Travis job, because log length 2019-04-22 02:19:27 +03:00
Peter Dimov
2122c7753c Avoid memcpy over a spinlock, because g++ 8 warns 2019-04-22 02:17:28 +03:00
Peter Dimov
7c76fb385d Add clang-win to Appveyor 2019-04-22 00:59:38 +03:00
Peter Dimov
372fac679b Remove _internal_aliasing_assign 2019-04-21 23:13:06 +03:00
Peter Dimov
e3adcaed1e Add revision history 2019-04-21 23:00:24 +03:00
Peter Dimov
016e682af6 Document weak_ptr aliasing constructors and empty 2019-04-21 22:52:44 +03:00
Peter Dimov
78e095d761 Disable tests that don't compile on msvc-8.0 2019-04-21 22:50:24 +03:00
Peter Dimov
eb8a91cb46 Add tests for the weak_ptr aliasing constructors 2019-04-21 22:44:09 +03:00
Peter Dimov
513cd15378 Add aliasing constructors to weak_ptr. Closes #67. 2019-04-21 22:43:04 +03:00
Peter Dimov
7bfa6a1f3d Fix typo 2019-04-21 21:33:55 +03:00
Peter Dimov
8120bb44cb Add rvalue pointer casts (closes #66) 2019-04-21 00:47:36 +03:00
Peter Dimov
18974ea2db Add cast tests to intrusive_ptr_test 2019-04-20 18:54:13 +03:00
Peter Dimov
2a4aca403a Merge branch 'develop' into feature/intrusive-ptr-tests 2019-04-20 18:15:31 +03:00
Peter Dimov
4d0d81477c Update msvc workarounds for 14.2 2019-04-20 18:15:05 +03:00
Peter Dimov
1725e26f70 Add assignment tests to intrusive_ptr_test 2019-04-20 18:02:11 +03:00
Peter Dimov
47fffaf11c Switch Appveyor to 2015 image 2019-04-14 18:24:21 +03:00
Peter Dimov
7f0323a347 Merge branch 'develop' of https://github.com/boostorg/smart_ptr into develop 2019-03-25 19:25:44 +02:00
Peter Dimov
6d8ea0f0c4 Remove project-id from doc/Jamfile 2019-03-25 19:25:33 +02:00
Glen Fernandes
d10299159a More asciidoctor changes
Reinstate the none/blank trick, but remove the blank line after it in local_shared_ptr.adoc that causes the problem. Also use that trick in place of the nested DLs which don't work with Asciidoctor 2
2019-03-24 23:41:08 -04:00
Glen Fernandes
adcab0e313 Update asciidoc to work with Asciidoctor 2.0 2019-03-24 20:28:17 -04:00
27 changed files with 1060 additions and 198 deletions

View File

@@ -107,7 +107,17 @@ matrix:
- os: linux - os: linux
compiler: g++-8 compiler: g++-8
env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14,17,2a env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=03,11,14
addons:
apt:
packages:
- g++-8
sources:
- ubuntu-toolchain-r-test
- os: linux
compiler: g++-8
env: TOOLSET=gcc COMPILER=g++-8 CXXSTD=17,2a
addons: addons:
apt: apt:
packages: packages:

View File

@@ -1,4 +1,4 @@
# Copyright 2016-2018 Peter Dimov # Copyright 2016-2019 Peter Dimov
# Distributed under the Boost Software License, Version 1.0. # Distributed under the Boost Software License, Version 1.0.
# (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt) # (See accompanying file LICENSE_1_0.txt or copy at http://boost.org/LICENSE_1_0.txt)
@@ -14,28 +14,28 @@ branches:
environment: environment:
matrix: matrix:
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0,msvc-12.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-14.0 TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
TOOLSET: msvc-12.0,msvc-14.0
ADDRMD: 32,64 ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
TOOLSET: msvc-14.1 TOOLSET: msvc-14.1,clang-win
CXXSTD: 14,17 CXXSTD: 14,17
ADDRMD: 32,64 ADDRMD: 32,64
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin\bin; ADDPATH: C:\cygwin\bin;
TOOLSET: gcc TOOLSET: gcc
CXXSTD: 03,11,14,1z CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\cygwin64\bin; ADDPATH: C:\cygwin64\bin;
TOOLSET: gcc TOOLSET: gcc
CXXSTD: 03,11,14,1z CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw\bin; ADDPATH: C:\mingw\bin;
TOOLSET: gcc TOOLSET: gcc
CXXSTD: 03,11,14,1z CXXSTD: 03,11,14,1z
- APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013 - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin; ADDPATH: C:\mingw-w64\x86_64-7.2.0-posix-seh-rt_v5-rev1\mingw64\bin;
TOOLSET: gcc TOOLSET: gcc
CXXSTD: 03,11,14,1z CXXSTD: 03,11,14,1z

View File

@@ -5,8 +5,6 @@
# See accompanying file LICENSE_1_0.txt or copy at # See accompanying file LICENSE_1_0.txt or copy at
# http://www.boost.org/LICENSE_1_0.txt # http://www.boost.org/LICENSE_1_0.txt
project doc/smart_ptr ;
import asciidoctor ; import asciidoctor ;
html smart_ptr.html : smart_ptr.adoc ; html smart_ptr.html : smart_ptr.adoc ;

View File

@@ -19,6 +19,8 @@ Greg Colvin, Beman Dawes, Peter Dimov, Glen Fernandes
include::smart_ptr/introduction.adoc[] include::smart_ptr/introduction.adoc[]
include::smart_ptr/changelog.adoc[]
include::smart_ptr/scoped_ptr.adoc[] include::smart_ptr/scoped_ptr.adoc[]
include::smart_ptr/scoped_array.adoc[] include::smart_ptr/scoped_array.adoc[]

View File

@@ -0,0 +1,19 @@
////
Copyright 2019 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
////
[#changelog]
# Revision History
:toc:
:toc-title:
:idprefix: changelog_
## Changes in 1.71.0
* Added aliasing constructors to `weak_ptr`
* Added `weak_ptr<T>::empty()`

View File

@@ -11,7 +11,9 @@ http://www.boost.org/LICENSE_1_0.txt
[#introduction] [#introduction]
# Introduction # Introduction
:idprefix: intro :toc:
:toc-title:
:idprefix: intro_
Smart pointers are objects which store pointers to dynamically allocated (heap) objects. Smart pointers are objects which store pointers to dynamically allocated (heap) objects.
They behave much like built-in {cpp} pointers except that they automatically delete the object They behave much like built-in {cpp} pointers except that they automatically delete the object

View File

@@ -77,7 +77,7 @@ namespace boost {
explicit operator bool () const noexcept; explicit operator bool () const noexcept;
void swap(intrusive_ptr & b) noexept; void swap(intrusive_ptr & b) noexcept;
}; };
template<class T, class U> template<class T, class U>

View File

@@ -78,12 +78,13 @@ namespace boost {
``` ```
intrusive_ref_counter() noexcept; intrusive_ref_counter() noexcept;
``` ```
::
``` ```
intrusive_ref_counter(const intrusive_ref_counter&) noexcept; intrusive_ref_counter(const intrusive_ref_counter&) noexcept;
``` ```
:: [none]
Postconditions::: `use_count() == 0`. * {blank}
+
Postconditions:: `use_count() == 0`.
NOTE: The pointer to the constructed object is expected to be passed to NOTE: The pointer to the constructed object is expected to be passed to
`intrusive_ptr` constructor, assignment operator or `reset` method, which `intrusive_ptr` constructor, assignment operator or `reset` method, which
@@ -94,8 +95,10 @@ would increment the reference counter.
``` ```
~intrusive_ref_counter(); ~intrusive_ref_counter();
``` ```
:: [none]
Effects::: Destroys the counter object. * {blank}
+
Effects:: Destroys the counter object.
NOTE: The destructor is protected so that the object can only be destroyed NOTE: The destructor is protected so that the object can only be destroyed
through the `Derived` class. through the `Derived` class.
@@ -105,16 +108,20 @@ through the `Derived` class.
``` ```
intrusive_ref_counter& operator=(const intrusive_ref_counter& v) noexcept; intrusive_ref_counter& operator=(const intrusive_ref_counter& v) noexcept;
``` ```
:: [none]
Effects::: Does nothing, reference counter is not modified. * {blank}
+
Effects:: Does nothing, reference counter is not modified.
### use_count ### use_count
``` ```
unsigned int use_count() const noexcept; unsigned int use_count() const noexcept;
``` ```
:: [none]
Returns::: The current value of the reference counter. * {blank}
+
Returns:: The current value of the reference counter.
NOTE: The returned value may not be actual in multi-threaded applications. NOTE: The returned value may not be actual in multi-threaded applications.
@@ -127,8 +134,10 @@ template<class Derived, class CounterPolicy>
void intrusive_ptr_add_ref( void intrusive_ptr_add_ref(
const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept; const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept;
``` ```
:: [none]
Effects::: Increments the reference counter. * {blank}
+
Effects:: Increments the reference counter.
### intrusive_ptr_release ### intrusive_ptr_release
@@ -137,6 +146,8 @@ template<class Derived, class CounterPolicy>
void intrusive_ptr_release( void intrusive_ptr_release(
const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept; const intrusive_ref_counter<Derived, CounterPolicy>* p) noexcept;
``` ```
:: [none]
Effects::: Decrements the reference counter. If the reference counter reaches * {blank}
+
Effects:: Decrements the reference counter. If the reference counter reaches
0, calls `delete static_cast<const Derived*>(p)`. 0, calls `delete static_cast<const Derived*>(p)`.

View File

@@ -716,4 +716,3 @@ template<class D, class T>
* {blank} * {blank}
+ +
Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter<D>( p )`, otherwise 0. Returns:: If `*this` owns a `shared_ptr` instance `p`, `get_deleter<D>( p )`, otherwise 0.

View File

@@ -174,17 +174,18 @@ the reference counts.
template<class T, class... Args> template<class T, class... Args>
shared_ptr<T> make_shared(Args&&... args); shared_ptr<T> make_shared(Args&&... args);
``` ```
::
``` ```
template<class T, class A, class... Args> template<class T, class A, class... Args>
shared_ptr<T> allocate_shared(const A& a, Args&&... args); shared_ptr<T> allocate_shared(const A& a, Args&&... args);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is not an array type. `T` is not an array type.
Returns::: A `shared_ptr` to an object of type `T`, constructed from Returns:: A `shared_ptr` to an object of type `T`, constructed from
`args\...`. `args\...`.
Examples::: Examples::
* `auto p = make_shared<int>();` * `auto p = make_shared<int>();`
* `auto p = make_shared<std::vector<int> >(16, 1);` * `auto p = make_shared<std::vector<int> >(16, 1);`
@@ -192,17 +193,18 @@ Examples:::
template<class T> template<class T>
shared_ptr<T> make_shared(std::size_t n); shared_ptr<T> make_shared(std::size_t n);
``` ```
::
``` ```
template<class T, class A> template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, std::size_t n); shared_ptr<T> allocate_shared(const A& a, std::size_t n);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[]`. `T` is an array type of the form `U[]`.
Returns::: A `shared_ptr` to a sequence of `n` value-initialized objects of Returns:: A `shared_ptr` to a sequence of `n` value-initialized objects of
type `U`. type `U`.
Examples::: Examples::
* `auto p = make_shared<double[]>(1024);` * `auto p = make_shared<double[]>(1024);`
* `auto p = make_shared<double[][2][2]>(6);` * `auto p = make_shared<double[][2][2]>(6);`
@@ -210,17 +212,18 @@ Examples:::
template<class T> template<class T>
shared_ptr<T> make_shared(); shared_ptr<T> make_shared();
``` ```
::
``` ```
template<class T, class A> template<class T, class A>
shared_ptr<T> allocate_shared(const A& a); shared_ptr<T> allocate_shared(const A& a);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[N]`. `T` is an array type of the form `U[N]`.
Returns::: A `shared_ptr` to a sequence of `N` value-initialized objects of Returns:: A `shared_ptr` to a sequence of `N` value-initialized objects of
type `U`. type `U`.
Examples::: Examples::
* `auto p = make_shared<double[1024]>();` * `auto p = make_shared<double[1024]>();`
* `auto p = make_shared<double[6][2][2]>();` * `auto p = make_shared<double[6][2][2]>();`
@@ -228,17 +231,18 @@ Examples:::
template<class T> shared_ptr<T> template<class T> shared_ptr<T>
make_shared(std::size_t n, const remove_extent_t<T>& v); make_shared(std::size_t n, const remove_extent_t<T>& v);
``` ```
::
``` ```
template<class T, class A> shared_ptr<T> template<class T, class A> shared_ptr<T>
allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v); allocate_shared(const A& a, std::size_t n, const remove_extent_t<T>& v);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[]`. `T` is an array type of the form `U[]`.
Returns::: A `shared_ptr` to a sequence of `n` objects of type `U`, each Returns:: A `shared_ptr` to a sequence of `n` objects of type `U`, each
initialized to `v`. initialized to `v`.
Examples::: Examples::
* `auto p = make_shared<double[]>(1024, 1.0);` * `auto p = make_shared<double[]>(1024, 1.0);`
* `auto p = make_shared<double[][2]>(6, {1.0, 0.0});` * `auto p = make_shared<double[][2]>(6, {1.0, 0.0});`
* `auto p = make_shared<std::vector<int>[]>(4, {1, 2});` * `auto p = make_shared<std::vector<int>[]>(4, {1, 2});`
@@ -247,17 +251,18 @@ Examples:::
template<class T> template<class T>
shared_ptr<T> make_shared(const remove_extent_t<T>& v); shared_ptr<T> make_shared(const remove_extent_t<T>& v);
``` ```
::
``` ```
template<class T, class A> template<class T, class A>
shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v); shared_ptr<T> allocate_shared(const A& a, const remove_extent_t<T>& v);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[N]`. `T` is an array type of the form `U[N]`.
Returns::: A `shared_ptr` to a sequence of `N` objects of type `U`, each Returns:: A `shared_ptr` to a sequence of `N` objects of type `U`, each
initialized to `v`. initialized to `v`.
Examples::: Examples::
* `auto p = make_shared<double[1024]>(1.0);` * `auto p = make_shared<double[1024]>(1.0);`
* `auto p = make_shared<double[6][2]>({1.0, 0.0});` * `auto p = make_shared<double[6][2]>({1.0, 0.0});`
* `auto p = make_shared<std::vector<int>[4]>({1, 2});` * `auto p = make_shared<std::vector<int>[4]>({1, 2});`
@@ -266,30 +271,32 @@ Examples:::
template<class T> template<class T>
shared_ptr<T> make_shared_noinit(); shared_ptr<T> make_shared_noinit();
``` ```
::
``` ```
template<class T, class A> template<class T, class A>
shared_ptr<T> allocate_shared_noinit(const A& a); shared_ptr<T> allocate_shared_noinit(const A& a);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is not an array type, or an array type of the `U[N]`. `T` is not an array type, or an array type of the `U[N]`.
Returns::: A `shared_ptr` to a default-initialized object of type `T`, or a Returns:: A `shared_ptr` to a default-initialized object of type `T`, or a
sequence of `N` default-initialized objects of type `U`, respectively. sequence of `N` default-initialized objects of type `U`, respectively.
Example::: `auto p = make_shared_noinit<double[1024]>();` Example:: `auto p = make_shared_noinit<double[1024]>();`
``` ```
template<class T> template<class T>
shared_ptr<T> make_shared_noinit(std::size_t n); shared_ptr<T> make_shared_noinit(std::size_t n);
``` ```
::
``` ```
template<class T, class A> template<class T, class A>
shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n); shared_ptr<T> allocate_shared_noinit(const A& a, std::size_t n);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[]`. `T` is an array type of the form `U[]`.
Returns::: A `shared_ptr` to a sequence of `_n_` default-initialized objects Returns:: A `shared_ptr` to a sequence of `_n_` default-initialized objects
of type `U`. of type `U`.
Example::: `auto p = make_shared_noinit<double[]>(1024);` Example:: `auto p = make_shared_noinit<double[]>(1024);`

View File

@@ -68,48 +68,58 @@ namespace boost {
template<class T, class... Args> template<class T, class... Args>
std::unique_ptr<T> make_unique(Args&&... args); std::unique_ptr<T> make_unique(Args&&... args);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is not an array type. `T` is not an array type.
Returns::: `std::unique_ptr<T>(new T(std::forward<Args>(args)\...)`. Returns:: `std::unique_ptr<T>(new T(std::forward<Args>(args)\...)`.
Example::: `auto p = make_unique<int>();` Example:: `auto p = make_unique<int>();`
``` ```
template<class T> template<class T>
std::unique_ptr<T> make_unique(remove_reference_t<T>&& v); std::unique_ptr<T> make_unique(remove_reference_t<T>&& v);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is not an array type. `T` is not an array type.
Returns::: `std::unique_ptr<T>(new T(std::move(v))`. Returns:: `std::unique_ptr<T>(new T(std::move(v))`.
Example::: `auto p = make_unique<std::vector<int> >({1, 2});` Example:: `auto p = make_unique<std::vector<int> >({1, 2});`
``` ```
template<class T> template<class T>
std::unique_ptr<T> make_unique(std::size_t n); std::unique_ptr<T> make_unique(std::size_t n);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[]`. `T` is an array type of the form `U[]`.
Returns::: `std::unique_ptr<U[]>(new U[n]())`. Returns:: `std::unique_ptr<U[]>(new U[n]())`.
Example::: `auto p = make_unique<double[]>(1024);` Example:: `auto p = make_unique<double[]>(1024);`
``` ```
template<class T> template<class T>
std::unique_ptr<T> make_unique_noinit(); std::unique_ptr<T> make_unique_noinit();
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is not an array type. `T` is not an array type.
Returns::: `std::unique_ptr<T>(new T)`. Returns:: `std::unique_ptr<T>(new T)`.
Example::: `auto p = make_unique_noinit<double[1024]>();` Example:: `auto p = make_unique_noinit<double[1024]>();`
``` ```
template<class T> template<class T>
std::unique_ptr<T> make_unique_noinit(std::size_t n); std::unique_ptr<T> make_unique_noinit(std::size_t n);
``` ```
:: [none]
Remarks::: These overloads shall only participate in overload resolution when * {blank}
+
Remarks:: These overloads shall only participate in overload resolution when
`T` is an array type of the form `U[]`. `T` is an array type of the form `U[]`.
Returns::: `std::unique_ptr<U[]>(new U[n])`. Returns:: `std::unique_ptr<U[]>(new U[n])`.
Example::: `auto p = make_unique_noinit<double[]>(1024);` Example:: `auto p = make_unique_noinit<double[]>(1024);`

View File

@@ -78,23 +78,29 @@ namespace boost {
``` ```
template<class T, class U> T* static_pointer_cast(U* p) noexcept; template<class T, class U> T* static_pointer_cast(U* p) noexcept;
``` ```
:: [none]
Returns::: `static_cast<T*>(p)` * {blank}
+
Returns:: `static_cast<T*>(p)`
``` ```
template<class T, class U> std::shared_ptr<T> template<class T, class U> std::shared_ptr<T>
static_pointer_cast(const std::shared_ptr<U>& p) noexcept; static_pointer_cast(const std::shared_ptr<U>& p) noexcept;
``` ```
:: [none]
Returns::: `std::static_pointer_cast<T>(p)` * {blank}
+
Returns:: `std::static_pointer_cast<T>(p)`
``` ```
template<class T, class U> std::unique_ptr<T> template<class T, class U> std::unique_ptr<T>
static_pointer_cast(std::unique_ptr<U>&& p) noexcept; static_pointer_cast(std::unique_ptr<U>&& p) noexcept;
``` ```
:: [none]
Requires::: The expression `static_cast<T*>((U*)0)` must be well-formed. * {blank}
Returns::: `std::unique_ptr<T>(static_cast<typename +
Requires:: The expression `static_cast<T*>((U*)0)` must be well-formed.
Returns:: `std::unique_ptr<T>(static_cast<typename
std::unique_ptr<T>::element_type*>(p.release()))`. std::unique_ptr<T>::element_type*>(p.release()))`.
CAUTION: The seemingly equivalent expression CAUTION: The seemingly equivalent expression
@@ -106,25 +112,31 @@ undefined behavior, attempting to delete the same object twice.
``` ```
template<class T, class U> T* dynamic_pointer_cast(U* p) noexcept; template<class T, class U> T* dynamic_pointer_cast(U* p) noexcept;
``` ```
:: [none]
Returns::: `dynamic_cast<T*>(p)` * {blank}
+
Returns:: `dynamic_cast<T*>(p)`
``` ```
template<class T, class U> std::shared_ptr<T> template<class T, class U> std::shared_ptr<T>
dynamic_pointer_cast(const std::shared_ptr<U>& p) noexcept; dynamic_pointer_cast(const std::shared_ptr<U>& p) noexcept;
``` ```
:: [none]
Returns::: `std::dynamic_pointer_cast<T>(p)` * {blank}
+
Returns:: `std::dynamic_pointer_cast<T>(p)`
``` ```
template<class T, class U> std::unique_ptr<T> template<class T, class U> std::unique_ptr<T>
dynamic_pointer_cast(std::unique_ptr<U>&& p) noexcept; dynamic_pointer_cast(std::unique_ptr<U>&& p) noexcept;
``` ```
:: [none]
Requires::: * {blank}
+
Requires::
* The expression `static_cast<T*>((U*)0)` must be well-formed. * The expression `static_cast<T*>((U*)0)` must be well-formed.
* `T` must have a virtual destructor. * `T` must have a virtual destructor.
Returns::: Returns::
* When `dynamic_cast<typename std::unique_ptr<T>::element_type*>(p.get())` * When `dynamic_cast<typename std::unique_ptr<T>::element_type*>(p.get())`
returns a non-zero value, `std::unique_ptr<T>(dynamic_cast<typename returns a non-zero value, `std::unique_ptr<T>(dynamic_cast<typename
std::unique_ptr<T>::element_type*>(p.release()));`. std::unique_ptr<T>::element_type*>(p.release()));`.
@@ -135,23 +147,29 @@ std::unique_ptr<T>::element_type*>(p.release()));`.
``` ```
template<class T, class U> T* const_pointer_cast(U* p) noexcept; template<class T, class U> T* const_pointer_cast(U* p) noexcept;
``` ```
:: [none]
Returns::: `const_cast<T*>(p)` * {blank}
+
Returns:: `const_cast<T*>(p)`
``` ```
template<class T, class U> std::shared_ptr<T> template<class T, class U> std::shared_ptr<T>
const_pointer_cast(const std::shared_ptr<U>& p) noexcept; const_pointer_cast(const std::shared_ptr<U>& p) noexcept;
``` ```
:: [none]
Returns::: `std::const_pointer_cast<T>(p)` * {blank}
+
Returns:: `std::const_pointer_cast<T>(p)`
``` ```
template<class T, class U> std::unique_ptr<T> template<class T, class U> std::unique_ptr<T>
const_pointer_cast(std::unique_ptr<U>&& p) noexcept; const_pointer_cast(std::unique_ptr<U>&& p) noexcept;
``` ```
:: [none]
Requires::: The expression `const_cast<T*>((U*)0)` must be well-formed. * {blank}
Returns::: `std::unique_ptr<T>(const_cast<typename +
Requires:: The expression `const_cast<T*>((U*)0)` must be well-formed.
Returns:: `std::unique_ptr<T>(const_cast<typename
std::unique_ptr<T>::element_type*>(p.release()))`. std::unique_ptr<T>::element_type*>(p.release()))`.
### reinterpret_pointer_cast ### reinterpret_pointer_cast
@@ -159,23 +177,29 @@ std::unique_ptr<T>::element_type*>(p.release()))`.
``` ```
template<class T, class U> T* reinterpret_pointer_cast(U* p) noexcept; template<class T, class U> T* reinterpret_pointer_cast(U* p) noexcept;
``` ```
:: [none]
Returns::: `reinterpret_cast<T*>(p)` * {blank}
+
Returns:: `reinterpret_cast<T*>(p)`
``` ```
template<class T, class U> std::shared_ptr<T> template<class T, class U> std::shared_ptr<T>
reinterpret_pointer_cast(const std::shared_ptr<U>& p) noexcept; reinterpret_pointer_cast(const std::shared_ptr<U>& p) noexcept;
``` ```
:: [none]
Returns::: `std::reinterpret_pointer_cast<T>(p)` * {blank}
+
Returns:: `std::reinterpret_pointer_cast<T>(p)`
``` ```
template<class T, class U> std::unique_ptr<T> template<class T, class U> std::unique_ptr<T>
reinterpret_pointer_cast(std::unique_ptr<U>&& p) noexcept; reinterpret_pointer_cast(std::unique_ptr<U>&& p) noexcept;
``` ```
:: [none]
Requires::: The expression `reinterpret_cast<T*>((U*)0)` must be well-formed. * {blank}
Returns::: `std::unique_ptr<T>(reinterpret_cast<typename +
Requires:: The expression `reinterpret_cast<T*>((U*)0)` must be well-formed.
Returns:: `std::unique_ptr<T>(reinterpret_cast<typename
std::unique_ptr<T>::element_type*>(p.release()))`. std::unique_ptr<T>::element_type*>(p.release()))`.
## Example ## Example
@@ -210,4 +234,4 @@ int main()
delete ptr; delete ptr;
} }
``` ```

View File

@@ -105,42 +105,50 @@ Type:: Provides the type of the stored pointer.
``` ```
explicit shared_array(T* p = 0); explicit shared_array(T* p = 0);
``` ```
:: [none]
Effects::: Constructs a `shared_array`, storing a copy of `p`, which must be a * {blank}
+
Effects:: Constructs a `shared_array`, storing a copy of `p`, which must be a
pointer to an array that was allocated via a C++ `new[]` expression or be 0. pointer to an array that was allocated via a C++ `new[]` expression or be 0.
Afterwards, the use count is 1 (even if `p == 0`; see `~shared_array`). Afterwards, the use count is 1 (even if `p == 0`; see `~shared_array`).
Requires::: `T` is a complete type. Requires:: `T` is a complete type.
Throws::: `std::bad_alloc`. If an exception is thrown, `delete[] p` is called. Throws:: `std::bad_alloc`. If an exception is thrown, `delete[] p` is called.
``` ```
template<class D> shared_array(T* p, D d); template<class D> shared_array(T* p, D d);
``` ```
:: [none]
Effects::: Constructs a `shared_array`, storing a copy of `p` and of `d`. * {blank}
+
Effects:: Constructs a `shared_array`, storing a copy of `p` and of `d`.
Afterwards, the use count is 1. When the the time comes to delete the array Afterwards, the use count is 1. When the the time comes to delete the array
pointed to by `p`, the object `d` is used in the statement `d(p)`. pointed to by `p`, the object `d` is used in the statement `d(p)`.
Requires::: Requires::
* `T` is a complete type. * `T` is a complete type.
* The copy constructor and destructor of `D` must not throw. * The copy constructor and destructor of `D` must not throw.
* Invoking the object `d` with parameter `p` must not throw. * Invoking the object `d` with parameter `p` must not throw.
Throws::: `std::bad_alloc`. If an exception is thrown, `d(p)` is called. Throws:: `std::bad_alloc`. If an exception is thrown, `d(p)` is called.
``` ```
shared_array(const shared_array& v) noexcept; shared_array(const shared_array& v) noexcept;
``` ```
:: [none]
Effects::: Constructs a `shared_array`, as if by storing a copy of the pointer * {blank}
+
Effects:: Constructs a `shared_array`, as if by storing a copy of the pointer
stored in `v`. Afterwards, the use count for all copies is 1 more than the stored in `v`. Afterwards, the use count for all copies is 1 more than the
initial use count. initial use count.
Requires::: `T` is a complete type. Requires:: `T` is a complete type.
### Destructor ### Destructor
``` ```
~shared_array() noexcept; ~shared_array() noexcept;
``` ```
:: [none]
Effects::: Decrements the use count. Then, if the use count is 0, deletes the * {blank}
+
Effects:: Decrements the use count. Then, if the use count is 0, deletes the
array pointed to by the stored pointer. Note that `delete[]` on a pointer with array pointed to by the stored pointer. Note that `delete[]` on a pointer with
a value of 0 is harmless. a value of 0 is harmless.
@@ -149,60 +157,70 @@ a value of 0 is harmless.
``` ```
shared_array& operator=(const shared_array& v) noexcept; shared_array& operator=(const shared_array& v) noexcept;
``` ```
:: [none]
Effects::: Constructs a new `shared_array` as described above, then replaces * {blank}
+
Effects:: Constructs a new `shared_array` as described above, then replaces
this `shared_array` with the new one, destroying the replaced object. this `shared_array` with the new one, destroying the replaced object.
Requires::: `T` is a complete type. Requires:: `T` is a complete type.
Returns::: `*this`. Returns:: `*this`.
### reset ### reset
``` ```
void reset(T* p = 0); void reset(T* p = 0);
``` ```
:: [none]
Effects::: Constructs a new `shared_array` as described above, then replaces * {blank}
+
Effects:: Constructs a new `shared_array` as described above, then replaces
this `shared_array` with the new one, destroying the replaced object. this `shared_array` with the new one, destroying the replaced object.
Requires::: `T` is a complete type. Requires:: `T` is a complete type.
Throws::: `std::bad_alloc`. If an exception is thrown, `delete[] p` is called. Throws:: `std::bad_alloc`. If an exception is thrown, `delete[] p` is called.
``` ```
template<class D> void reset(T* p, D d); template<class D> void reset(T* p, D d);
``` ```
:: [none]
Effects::: Constructs a new `shared_array` as described above, then replaces * {blank}
+
Effects:: Constructs a new `shared_array` as described above, then replaces
this `shared_array` with the new one, destroying the replaced object. this `shared_array` with the new one, destroying the replaced object.
Requires::: Requires::
* `T` is a complete type. * `T` is a complete type.
* The copy constructor of `D` must not throw. * The copy constructor of `D` must not throw.
Throws::: `std::bad_alloc`. If an exception is thrown, `d(p)` is called. Throws:: `std::bad_alloc`. If an exception is thrown, `d(p)` is called.
### Indexing ### Indexing
``` ```
T& operator[](std::ptrdiff_t n) const noexcept; T& operator[](std::ptrdiff_t n) const noexcept;
``` ```
Returns::: A reference to element `n` of the array pointed to by the stored Returns:: A reference to element `n` of the array pointed to by the stored
pointer. Behavior is undefined and almost certainly undesirable if the stored pointer. Behavior is undefined and almost certainly undesirable if the stored
pointer is 0, or if `n` is less than 0 or is greater than or equal to the pointer is 0, or if `n` is less than 0 or is greater than or equal to the
number of elements in the array. number of elements in the array.
Requires::: `T` is a complete type. Requires:: `T` is a complete type.
### get ### get
``` ```
T* get() const noexcept; T* get() const noexcept;
``` ```
:: [none]
Returns::: The stored pointer. * {blank}
+
Returns:: The stored pointer.
### unique ### unique
``` ```
bool unique() const noexcept; bool unique() const noexcept;
``` ```
:: [none]
Returns::: `true` if no other `shared_array` is sharing ownership of the * {blank}
+
Returns:: `true` if no other `shared_array` is sharing ownership of the
stored pointer, `false` otherwise. stored pointer, `false` otherwise.
### use_count ### use_count
@@ -210,8 +228,10 @@ stored pointer, `false` otherwise.
``` ```
long use_count() const noexcept; long use_count() const noexcept;
``` ```
:: [none]
Returns::: The number of `shared_array` objects sharing ownership of the * {blank}
+
Returns:: The number of `shared_array` objects sharing ownership of the
stored pointer. stored pointer.
### Conversions ### Conversions
@@ -219,17 +239,21 @@ stored pointer.
``` ```
explicit operator bool() const noexcept; explicit operator bool() const noexcept;
``` ```
:: [none]
Returns::: `get() != 0`. * {blank}
Requires::: `T` is a complete type. +
Returns:: `get() != 0`.
Requires:: `T` is a complete type.
### swap ### swap
``` ```
void swap(shared_array<T>& b) noexcept; void swap(shared_array<T>& b) noexcept;
``` ```
:: [none]
Effects::: Exchanges the contents of the two smart pointers. * {blank}
+
Effects:: Exchanges the contents of the two smart pointers.
## Free Functions ## Free Functions
@@ -247,8 +271,10 @@ template<class T> bool
template<class T> bool template<class T> bool
operator<(const shared_array<T>& a, const shared_array<T>& b) noexcept; operator<(const shared_array<T>& a, const shared_array<T>& b) noexcept;
``` ```
:: [none]
Returns::: The result of comparing the stored pointers of the two smart * {blank}
+
Returns:: The result of comparing the stored pointers of the two smart
pointers. pointers.
NOTE: The `operator<` overload is provided to define an ordering so that NOTE: The `operator<` overload is provided to define an ordering so that
@@ -265,6 +291,8 @@ mandates that relational operations on pointers are unspecified (5.9
template<class T> template<class T>
void swap(shared_array<T>& a, shared_array<T>& b) noexcept; void swap(shared_array<T>& a, shared_array<T>& b) noexcept;
``` ```
:: [none]
Returns::: `a.swap(b)`. * {blank}
Requires::: `T` is a complete type. +
Returns:: `a.swap(b)`.
Requires:: `T` is a complete type.

View File

@@ -132,7 +132,6 @@ namespace boost {
template<class Y> shared_ptr(shared_ptr<Y> && r) noexcept; template<class Y> shared_ptr(shared_ptr<Y> && r) noexcept;
template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p) noexcept; template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p) noexcept;
template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p) noexcept; template<class Y> shared_ptr(shared_ptr<Y> && r, element_type * p) noexcept;
template<class Y> explicit shared_ptr(weak_ptr<Y> const & r); template<class Y> explicit shared_ptr(weak_ptr<Y> const & r);
@@ -373,7 +372,7 @@ template<class Y> shared_ptr(shared_ptr<Y> const & r, element_type * p) noexcept
[none] [none]
* {blank} * {blank}
+ +
Effects:: constructs a `shared_ptr` that shares ownership with `r` and stores `p`. Effects:: Copy-constructs a `shared_ptr` from `r`, while storing `p` instead.
Postconditions:: `get() == p && use_count() == r.use_count()`. Postconditions:: `get() == p && use_count() == r.use_count()`.

View File

@@ -88,6 +88,10 @@ namespace boost {
weak_ptr(weak_ptr && r) noexcept; weak_ptr(weak_ptr && r) noexcept;
template<class Y> weak_ptr(shared_ptr<Y> const & r, element_type * p) noexcept;
template<class Y> weak_ptr(weak_ptr<Y> const & r, element_type * p) noexcept;
template<class Y> weak_ptr(weak_ptr<Y> && r, element_type * p) noexcept;
~weak_ptr() noexcept; ~weak_ptr() noexcept;
weak_ptr & operator=(weak_ptr const & r) noexcept; weak_ptr & operator=(weak_ptr const & r) noexcept;
@@ -98,6 +102,8 @@ namespace boost {
long use_count() const noexcept; long use_count() const noexcept;
bool expired() const noexcept; bool expired() const noexcept;
bool empty() const noexcept;
shared_ptr<T> lock() const noexcept; shared_ptr<T> lock() const noexcept;
void reset() noexcept; void reset() noexcept;
@@ -157,6 +163,21 @@ weak_ptr(weak_ptr && r) noexcept;
Effects:: Constructs a `weak_ptr` that has the value `r` held. Effects:: Constructs a `weak_ptr` that has the value `r` held.
Postconditions:: `r` is empty. Postconditions:: `r` is empty.
### aliasing constructors
```
template<class Y> weak_ptr(shared_ptr<Y> const & r, element_type * p) noexcept;
```
```
template<class Y> weak_ptr(weak_ptr<Y> const & r, element_type * p) noexcept;
```
```
template<class Y> weak_ptr(weak_ptr<Y> && r, element_type * p) noexcept;
```
Effects:: Constructs a `weak_ptr` from `r` as if by using the corresponding converting/copy/move constructor, but stores `p` instead.
Postconditions:: `use_count() == r.use_count()`. When `!expired()`, `shared_ptr<T>(*this).get() == p`.
NOTE: These constructors are an extension, not present in `std::weak_ptr`.
### destructor ### destructor
``` ```
~weak_ptr() noexcept; ~weak_ptr() noexcept;
@@ -204,6 +225,17 @@ bool expired() const noexcept;
+ +
Returns:: `use_count() == 0`. Returns:: `use_count() == 0`.
### empty
```
bool empty() const noexcept;
```
[none]
* {blank}
+
Returns:: `true` when `*this` is empty, `false` otherwise.
NOTE: This function is an extension, not present in `std::weak_ptr`.
### lock ### lock
``` ```
shared_ptr<T> lock() const noexcept; shared_ptr<T> lock() const noexcept;

View File

@@ -63,6 +63,11 @@ public:
{ {
} }
atomic_shared_ptr( shared_ptr<T> p ) BOOST_SP_NOEXCEPT
: p_( std::move( p ) ), l_ BOOST_DETAIL_SPINLOCK_INIT
{
}
#else #else
atomic_shared_ptr() BOOST_SP_NOEXCEPT atomic_shared_ptr() BOOST_SP_NOEXCEPT
@@ -71,8 +76,6 @@ public:
std::memcpy( &l_, &init, sizeof( init ) ); std::memcpy( &l_, &init, sizeof( init ) );
} }
#endif
atomic_shared_ptr( shared_ptr<T> p ) BOOST_SP_NOEXCEPT atomic_shared_ptr( shared_ptr<T> p ) BOOST_SP_NOEXCEPT
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES ) #if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
: p_( std::move( p ) ) : p_( std::move( p ) )
@@ -84,6 +87,8 @@ public:
std::memcpy( &l_, &init, sizeof( init ) ); std::memcpy( &l_, &init, sizeof( init ) );
} }
#endif
atomic_shared_ptr& operator=( shared_ptr<T> r ) BOOST_SP_NOEXCEPT atomic_shared_ptr& operator=( shared_ptr<T> r ) BOOST_SP_NOEXCEPT
{ {
boost::detail::spinlock::scoped_lock lock( l_ ); boost::detail::spinlock::scoped_lock lock( l_ );

View File

@@ -144,8 +144,7 @@ template<typename T>
boost::weak_ptr<T> weak_from_raw(T *p) boost::weak_ptr<T> weak_from_raw(T *p)
{ {
BOOST_ASSERT(p != 0); BOOST_ASSERT(p != 0);
boost::weak_ptr<T> result; boost::weak_ptr<T> result(p->enable_shared_from_raw::weak_from_this(), p);
result._internal_aliasing_assign(p->enable_shared_from_raw::weak_from_this(), p);
return result; return result;
} }

View File

@@ -297,6 +297,8 @@ template<class T> T * get_pointer(intrusive_ptr<T> const & p) BOOST_SP_NOEXCEPT
return p.get(); return p.get();
} }
// pointer casts
template<class T, class U> intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & p) template<class T, class U> intrusive_ptr<T> static_pointer_cast(intrusive_ptr<U> const & p)
{ {
return static_cast<T *>(p.get()); return static_cast<T *>(p.get());
@@ -312,6 +314,31 @@ template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast(intrusive_ptr<U
return dynamic_cast<T *>(p.get()); return dynamic_cast<T *>(p.get());
} }
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class T, class U> intrusive_ptr<T> static_pointer_cast( intrusive_ptr<U> && p ) BOOST_SP_NOEXCEPT
{
return intrusive_ptr<T>( static_cast<T*>( p.detach() ), false );
}
template<class T, class U> intrusive_ptr<T> const_pointer_cast( intrusive_ptr<U> && p ) BOOST_SP_NOEXCEPT
{
return intrusive_ptr<T>( const_cast<T*>( p.detach() ), false );
}
template<class T, class U> intrusive_ptr<T> dynamic_pointer_cast( intrusive_ptr<U> && p ) BOOST_SP_NOEXCEPT
{
T * p2 = dynamic_cast<T*>( p.get() );
intrusive_ptr<T> r( p2, false );
if( p2 ) p.detach();
return r;
}
#endif // defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
// operator<< // operator<<
#if !defined(BOOST_NO_IOSTREAM) #if !defined(BOOST_NO_IOSTREAM)

View File

@@ -137,6 +137,23 @@ public:
boost::detail::sp_assert_convertible< Y, T >(); boost::detail::sp_assert_convertible< Y, T >();
} }
// aliasing
template<class Y> weak_ptr(shared_ptr<Y> const & r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( r.pn )
{
}
template<class Y> weak_ptr(weak_ptr<Y> const & r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( r.pn )
{
}
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
template<class Y> weak_ptr(weak_ptr<Y> && r, element_type * p) BOOST_SP_NOEXCEPT: px( p ), pn( std::move( r.pn ) )
{
}
#endif
#if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300) #if !defined(BOOST_MSVC) || (BOOST_MSVC >= 1300)
template<class Y> template<class Y>
@@ -194,6 +211,11 @@ public:
return pn.empty(); return pn.empty();
} }
bool empty() const BOOST_SP_NOEXCEPT // extension, not in std::weak_ptr
{
return pn.empty();
}
void reset() BOOST_SP_NOEXCEPT void reset() BOOST_SP_NOEXCEPT
{ {
this_type().swap(*this); this_type().swap(*this);
@@ -205,13 +227,6 @@ public:
pn.swap(other.pn); pn.swap(other.pn);
} }
template<typename Y>
void _internal_aliasing_assign(weak_ptr<Y> const & r, element_type * px2) BOOST_SP_NOEXCEPT
{
px = px2;
pn = r.pn;
}
template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_SP_NOEXCEPT template<class Y> bool owner_before( weak_ptr<Y> const & rhs ) const BOOST_SP_NOEXCEPT
{ {
return pn < rhs.pn; return pn < rhs.pn;

View File

@@ -158,18 +158,18 @@ compile-fail array_fail_dereference.cpp ;
compile-fail array_fail_member_access.cpp ; compile-fail array_fail_member_access.cpp ;
compile-fail array_fail_array_access.cpp ; compile-fail array_fail_array_access.cpp ;
run make_shared_array_test.cpp ; run make_shared_array_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run make_shared_arrays_test.cpp ; # <cxxflags>-fno-deduce-init-list no longer needed for gcc-4.6 run make_shared_arrays_test.cpp ; # <cxxflags>-fno-deduce-init-list no longer needed for gcc-4.6
run make_shared_array_throws_test.cpp ; run make_shared_array_throws_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run make_shared_array_esft_test.cpp ; run make_shared_array_esft_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run make_shared_array_noinit_test.cpp ; run make_shared_array_noinit_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run make_shared_array_value_test.cpp ; run make_shared_array_value_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run allocate_shared_array_test.cpp ; run allocate_shared_array_test.cpp ;
run allocate_shared_arrays_test.cpp ; # <cxxflags>-fno-deduce-init-list no longer needed for gcc-4.6 run allocate_shared_arrays_test.cpp ; # <cxxflags>-fno-deduce-init-list no longer needed for gcc-4.6
run allocate_shared_array_throws_test.cpp ; run allocate_shared_array_throws_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run allocate_shared_array_esft_test.cpp ; run allocate_shared_array_esft_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run allocate_shared_array_noinit_test.cpp ; run allocate_shared_array_noinit_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run allocate_shared_array_value_test.cpp ; run allocate_shared_array_value_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run allocate_shared_array_construct_test.cpp ; run allocate_shared_array_construct_test.cpp ;
run make_unique_test.cpp ; run make_unique_test.cpp ;
@@ -236,7 +236,7 @@ run shared_ptr_fn_test.cpp ;
run get_deleter_test2.cpp ; run get_deleter_test2.cpp ;
run get_deleter_test3.cpp ; run get_deleter_test3.cpp ;
run get_deleter_array_test2.cpp ; run get_deleter_array_test2.cpp ;
run get_deleter_array_test3.cpp ; run get_deleter_array_test3.cpp : : : <toolset>msvc-8.0:<build>no ;
run sp_convertible_test2.cpp ; run sp_convertible_test2.cpp ;
@@ -275,7 +275,7 @@ run local_sp_fn_test.cpp ;
run lsp_convertible_test.cpp ; run lsp_convertible_test.cpp ;
run lsp_convertible_test2.cpp ; run lsp_convertible_test2.cpp ;
run make_shared_array_tmp_test.cpp ; run make_shared_array_tmp_test.cpp : : : <toolset>msvc-8.0:<build>no ;
run lw_thread_test.cpp : : : <threading>multi ; run lw_thread_test.cpp : : : <threading>multi ;
@@ -306,3 +306,6 @@ run abi_test_main.cpp abi_test_nt : : : : abi_test_mt_nt ;
run abi_test_main.cpp abi_test_mt/<cxxstd>0x : : : <cxxstd>98 : abi_test_03_11 ; run abi_test_main.cpp abi_test_mt/<cxxstd>0x : : : <cxxstd>98 : abi_test_03_11 ;
run abi_test_main.cpp abi_test_mt/<cxxstd>98 : : : <cxxstd>0x : abi_test_11_03 ; run abi_test_main.cpp abi_test_mt/<cxxstd>98 : : : <cxxstd>0x : abi_test_11_03 ;
run weak_ptr_alias_test.cpp ;
run weak_ptr_alias_move_test.cpp ;

View File

@@ -18,10 +18,10 @@
BOOST_PRAGMA_MESSAGE("Skipping test due to BOOST_NO_CXX11_CONSTEXPR") BOOST_PRAGMA_MESSAGE("Skipping test due to BOOST_NO_CXX11_CONSTEXPR")
int main() {} int main() {}
#elif BOOST_WORKAROUND( BOOST_MSVC, < 1920 ) #elif BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
// MSVC does not implement static initialization for constexpr // MSVC does not implement static initialization for constexpr constructors
BOOST_PRAGMA_MESSAGE("Skipping test due to BOOST_MSVC < 1920") BOOST_PRAGMA_MESSAGE("Skipping test due to BOOST_MSVC < 1930")
int main() {} int main() {}
#elif defined(__clang__) && defined( BOOST_NO_CXX14_CONSTEXPR ) #elif defined(__clang__) && defined( BOOST_NO_CXX14_CONSTEXPR )

View File

@@ -41,7 +41,7 @@ class base
{ {
private: private:
boost::detail::atomic_count use_count_; mutable boost::detail::atomic_count use_count_;
base(base const &); base(base const &);
base & operator=(base const &); base & operator=(base const &);
@@ -69,24 +69,24 @@ public:
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
inline friend void intrusive_ptr_add_ref(base * p) inline friend void intrusive_ptr_add_ref(base const * p)
{ {
++p->use_count_; ++p->use_count_;
} }
inline friend void intrusive_ptr_release(base * p) inline friend void intrusive_ptr_release(base const * p)
{ {
if(--p->use_count_ == 0) delete p; if(--p->use_count_ == 0) delete p;
} }
#else #else
void add_ref() void add_ref() const
{ {
++use_count_; ++use_count_;
} }
void release() void release() const
{ {
if(--use_count_ == 0) delete this; if(--use_count_ == 0) delete this;
} }
@@ -103,12 +103,12 @@ long base::instances = 0;
namespace boost namespace boost
{ {
inline void intrusive_ptr_add_ref(N::base * p) inline void intrusive_ptr_add_ref(N::base const * p)
{ {
p->add_ref(); p->add_ref();
} }
inline void intrusive_ptr_release(N::base * p) inline void intrusive_ptr_release(N::base const * p)
{ {
p->release(); p->release();
} }
@@ -209,6 +209,58 @@ int main()
BOOST_TEST( N::base::instances == 0 ); BOOST_TEST( N::base::instances == 0 );
} }
{
boost::intrusive_ptr<X> px( new Y );
X * px2 = px.get();
boost::intrusive_ptr<Y> py = boost::static_pointer_cast<Y>( std::move( px ) );
BOOST_TEST( py.get() == px2 );
BOOST_TEST( px.get() == 0 );
BOOST_TEST( py->use_count() == 1 );
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X const> px( new X );
X const * px2 = px.get();
boost::intrusive_ptr<X> px3 = boost::const_pointer_cast<X>( std::move( px ) );
BOOST_TEST( px3.get() == px2 );
BOOST_TEST( px.get() == 0 );
BOOST_TEST( px3->use_count() == 1 );
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> px( new Y );
X * px2 = px.get();
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( std::move( px ) );
BOOST_TEST( py.get() == px2 );
BOOST_TEST( px.get() == 0 );
BOOST_TEST( py->use_count() == 1 );
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> px( new X );
X * px2 = px.get();
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( std::move( px ) );
BOOST_TEST( py.get() == 0 );
BOOST_TEST( px.get() == px2 );
BOOST_TEST( px->use_count() == 1 );
}
BOOST_TEST( N::base::instances == 0 );
return boost::report_errors(); return boost::report_errors();
} }

View File

@@ -42,7 +42,7 @@ class base
{ {
private: private:
boost::detail::atomic_count use_count_; mutable boost::detail::atomic_count use_count_;
base(base const &); base(base const &);
base & operator=(base const &); base & operator=(base const &);
@@ -70,24 +70,24 @@ public:
#if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP) #if !defined(BOOST_NO_ARGUMENT_DEPENDENT_LOOKUP)
inline friend void intrusive_ptr_add_ref(base * p) inline friend void intrusive_ptr_add_ref(base const * p)
{ {
++p->use_count_; ++p->use_count_;
} }
inline friend void intrusive_ptr_release(base * p) inline friend void intrusive_ptr_release(base const * p)
{ {
if(--p->use_count_ == 0) delete p; if(--p->use_count_ == 0) delete p;
} }
#else #else
void add_ref() void add_ref() const
{ {
++use_count_; ++use_count_;
} }
void release() void release() const
{ {
if(--use_count_ == 0) delete this; if(--use_count_ == 0) delete this;
} }
@@ -104,12 +104,12 @@ long base::instances = 0;
namespace boost namespace boost
{ {
inline void intrusive_ptr_add_ref(N::base * p) inline void intrusive_ptr_add_ref(N::base const * p)
{ {
p->add_ref(); p->add_ref();
} }
inline void intrusive_ptr_release(N::base * p) inline void intrusive_ptr_release(N::base const * p)
{ {
p->release(); p->release();
} }
@@ -303,14 +303,211 @@ namespace n_assignment
void copy_assignment() void copy_assignment()
{ {
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> p1;
p1 = p1;
BOOST_TEST(p1 == p1);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
boost::intrusive_ptr<X> p2;
p1 = p2;
BOOST_TEST(p1 == p2);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
boost::intrusive_ptr<X> p3(p1);
p1 = p3;
BOOST_TEST(p1 == p3);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
BOOST_TEST(N::base::instances == 0);
boost::intrusive_ptr<X> p4(new X);
BOOST_TEST(N::base::instances == 1);
p1 = p4;
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p1 == p4);
BOOST_TEST(p1->use_count() == 2);
p1 = p2;
BOOST_TEST(p1 == p2);
BOOST_TEST(N::base::instances == 1);
p4 = p3;
BOOST_TEST(p4 == p3);
BOOST_TEST(N::base::instances == 0);
}
} }
void conversion_assignment() void conversion_assignment()
{ {
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> p1;
boost::intrusive_ptr<Y> p2;
p1 = p2;
BOOST_TEST(p1 == p2);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
BOOST_TEST(N::base::instances == 0);
boost::intrusive_ptr<Y> p4(new Y);
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p4->use_count() == 1);
boost::intrusive_ptr<X> p5(p4);
BOOST_TEST(p4->use_count() == 2);
p1 = p4;
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p1 == p4);
BOOST_TEST(p1->use_count() == 3);
BOOST_TEST(p4->use_count() == 3);
p1 = p2;
BOOST_TEST(p1 == p2);
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p4->use_count() == 2);
p4 = p2;
p5 = p2;
BOOST_TEST(p4 == p2);
BOOST_TEST(N::base::instances == 0);
}
} }
void pointer_assignment() void pointer_assignment()
{ {
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> p1;
p1 = p1.get();
BOOST_TEST(p1 == p1);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
boost::intrusive_ptr<X> p2;
p1 = p2.get();
BOOST_TEST(p1 == p2);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
boost::intrusive_ptr<X> p3(p1);
p1 = p3.get();
BOOST_TEST(p1 == p3);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
BOOST_TEST(N::base::instances == 0);
boost::intrusive_ptr<X> p4(new X);
BOOST_TEST(N::base::instances == 1);
p1 = p4.get();
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p1 == p4);
BOOST_TEST(p1->use_count() == 2);
p1 = p2.get();
BOOST_TEST(p1 == p2);
BOOST_TEST(N::base::instances == 1);
p4 = p3.get();
BOOST_TEST(p4 == p3);
BOOST_TEST(N::base::instances == 0);
}
{
boost::intrusive_ptr<X> p1;
boost::intrusive_ptr<Y> p2;
p1 = p2.get();
BOOST_TEST(p1 == p2);
BOOST_TEST(p1? false: true);
BOOST_TEST(!p1);
BOOST_TEST(p1.get() == 0);
BOOST_TEST(N::base::instances == 0);
boost::intrusive_ptr<Y> p4(new Y);
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p4->use_count() == 1);
boost::intrusive_ptr<X> p5(p4);
BOOST_TEST(p4->use_count() == 2);
p1 = p4.get();
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p1 == p4);
BOOST_TEST(p1->use_count() == 3);
BOOST_TEST(p4->use_count() == 3);
p1 = p2.get();
BOOST_TEST(p1 == p2);
BOOST_TEST(N::base::instances == 1);
BOOST_TEST(p4->use_count() == 2);
p4 = p2.get();
p5 = p2.get();
BOOST_TEST(p4 == p2);
BOOST_TEST(N::base::instances == 0);
}
} }
void test() void test()
@@ -707,15 +904,137 @@ namespace n_static_cast
void test() void test()
{ {
{
boost::intrusive_ptr<X> px(new Y);
boost::intrusive_ptr<Y> py = boost::static_pointer_cast<Y>(px);
BOOST_TEST(px.get() == py.get());
BOOST_TEST(px->use_count() == 2);
BOOST_TEST(py->use_count() == 2);
boost::intrusive_ptr<X> px2(py);
BOOST_TEST(px2.get() == px.get());
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<Y> py = boost::static_pointer_cast<Y>( boost::intrusive_ptr<X>(new Y) );
BOOST_TEST(py.get() != 0);
BOOST_TEST(py->use_count() == 1);
}
BOOST_TEST( N::base::instances == 0 );
} }
} // namespace n_static_cast } // namespace n_static_cast
namespace n_const_cast
{
void test()
{
{
boost::intrusive_ptr<X const> px;
boost::intrusive_ptr<X> px2 = boost::const_pointer_cast<X>(px);
BOOST_TEST(px2.get() == 0);
}
{
boost::intrusive_ptr<X> px2 = boost::const_pointer_cast<X>( boost::intrusive_ptr<X const>() );
BOOST_TEST(px2.get() == 0);
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X const> px(new X);
boost::intrusive_ptr<X> px2 = boost::const_pointer_cast<X>(px);
BOOST_TEST(px2.get() == px.get());
BOOST_TEST(px2->use_count() == 2);
BOOST_TEST(px->use_count() == 2);
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> px = boost::const_pointer_cast<X>( boost::intrusive_ptr<X const>(new X) );
BOOST_TEST(px.get() != 0);
BOOST_TEST(px->use_count() == 1);
}
BOOST_TEST( N::base::instances == 0 );
}
} // namespace n_const_cast
namespace n_dynamic_cast namespace n_dynamic_cast
{ {
void test() void test()
{ {
{
boost::intrusive_ptr<X> px;
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>(px);
BOOST_TEST(py.get() == 0);
}
{
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( boost::intrusive_ptr<X>() );
BOOST_TEST(py.get() == 0);
}
{
boost::intrusive_ptr<X> px(static_cast<X*>(0));
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>(px);
BOOST_TEST(py.get() == 0);
}
{
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( boost::intrusive_ptr<X>(static_cast<X*>(0)) );
BOOST_TEST(py.get() == 0);
}
{
boost::intrusive_ptr<X> px(new X);
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>(px);
BOOST_TEST(py.get() == 0);
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( boost::intrusive_ptr<X>(new X) );
BOOST_TEST(py.get() == 0);
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> px(new Y);
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>(px);
BOOST_TEST(py.get() == px.get());
BOOST_TEST(py->use_count() == 2);
BOOST_TEST(px->use_count() == 2);
}
BOOST_TEST( N::base::instances == 0 );
{
boost::intrusive_ptr<X> px(new Y);
boost::intrusive_ptr<Y> py = boost::dynamic_pointer_cast<Y>( boost::intrusive_ptr<X>(new Y) );
BOOST_TEST(py.get() != 0);
BOOST_TEST(py->use_count() == 1);
}
BOOST_TEST( N::base::instances == 0 );
} }
} // namespace n_dynamic_cast } // namespace n_dynamic_cast
@@ -779,6 +1098,7 @@ int main()
n_swap::test(); n_swap::test();
n_comparison::test(); n_comparison::test();
n_static_cast::test(); n_static_cast::test();
n_const_cast::test();
n_dynamic_cast::test(); n_dynamic_cast::test();
n_transitive::test(); n_transitive::test();

View File

@@ -17,7 +17,7 @@
# undef HAVE_CONSTEXPR_INIT # undef HAVE_CONSTEXPR_INIT
#endif #endif
#if BOOST_WORKAROUND( BOOST_MSVC, < 1920 ) #if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
# undef HAVE_CONSTEXPR_INIT # undef HAVE_CONSTEXPR_INIT
#endif #endif

View File

@@ -17,7 +17,7 @@
# undef HAVE_CONSTEXPR_INIT # undef HAVE_CONSTEXPR_INIT
#endif #endif
#if BOOST_WORKAROUND( BOOST_MSVC, < 1920 ) #if BOOST_WORKAROUND( BOOST_MSVC, < 1930 )
# undef HAVE_CONSTEXPR_INIT # undef HAVE_CONSTEXPR_INIT
#endif #endif

View File

@@ -0,0 +1,97 @@
// weak_ptr_alias_move_test.cpp
//
// Copyright 2007, 2019 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 <boost/core/lightweight_test.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/config.hpp>
#include <memory>
#include <cstddef>
#if !defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
class incomplete;
struct X
{
int v_;
explicit X( int v ): v_( v )
{
}
~X()
{
v_ = 0;
}
};
template<class P1, class P2> bool share_ownership( P1 const& p1, P2 const& p2 )
{
return !p1.owner_before( p2 ) && !p2.owner_before( p1 );
}
int main()
{
{
boost::shared_ptr<float> p( new float );
boost::weak_ptr<float> p2( p );
int m2 = 0;
boost::weak_ptr<int const volatile> p3( std::move( p2 ), &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
BOOST_TEST( p2.empty() );
}
{
boost::shared_ptr<incomplete> p;
boost::weak_ptr<incomplete> p2( p );
int m2 = 0;
boost::weak_ptr<int const volatile> p3( std::move( p2 ), &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
BOOST_TEST( p2.empty() );
}
{
boost::shared_ptr<X> p( new X( 5 ) );
boost::weak_ptr<X> p2( p );
boost::weak_ptr<int const volatile> p3( std::move( p2 ), &p2.lock()->v_ );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == &p->v_ );
BOOST_TEST( p2.empty() );
p.reset();
BOOST_TEST( p3.expired() );
}
return boost::report_errors();
}
#else // defined( BOOST_NO_CXX11_RVALUE_REFERENCES )
int main()
{
return 0;
}
#endif

View File

@@ -0,0 +1,203 @@
// weak_ptr_alias_test.cpp
//
// Copyright 2007, 2019 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 <boost/core/lightweight_test.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/shared_ptr.hpp>
#include <memory>
#include <cstddef>
//
class incomplete;
struct X
{
int v_;
explicit X( int v ): v_( v )
{
}
~X()
{
v_ = 0;
}
};
template<class P1, class P2> bool share_ownership( P1 const& p1, P2 const& p2 )
{
return !p1.owner_before( p2 ) && !p2.owner_before( p1 );
}
int main()
{
{
boost::shared_ptr<double> p( new double );
float m = 0;
boost::weak_ptr<float> p2( p, &m );
BOOST_TEST( p2.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p2 ) );
BOOST_TEST( p2.lock().get() == &m );
{
int m2 = 0;
boost::weak_ptr<int> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<int const> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<int volatile> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<void> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<void> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<void const volatile> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
{
int m2 = 0;
boost::weak_ptr<void const volatile> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == &m2 );
}
}
{
boost::shared_ptr<incomplete> p;
float m = 0;
boost::weak_ptr<float> p2( p, &m );
BOOST_TEST( p2.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p2 ) );
{
int m2 = 0;
boost::weak_ptr<int> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<int const> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<int volatile> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<void> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<void> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<void const volatile> p3( p, &m2 );
BOOST_TEST( p3.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
{
int m2 = 0;
boost::weak_ptr<void const volatile> p3( p2, &m2 );
BOOST_TEST( p3.use_count() == p2.use_count() );
BOOST_TEST( share_ownership( p2, p3 ) );
BOOST_TEST( p3.lock().get() == 0 );
}
}
{
boost::shared_ptr<X> p( new X( 5 ) );
boost::weak_ptr<int const> p2( p, &p->v_ );
BOOST_TEST( p2.use_count() == p.use_count() );
BOOST_TEST( share_ownership( p, p2 ) );
BOOST_TEST( p2.lock().get() == &p->v_ );
p.reset();
BOOST_TEST( p2.expired() );
}
return boost::report_errors();
}