forked from boostorg/smart_ptr
235 lines
7.5 KiB
Plaintext
235 lines
7.5 KiB
Plaintext
////
|
|
Copyright 2017 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
|
|
////
|
|
|
|
[#scoped_ptr]
|
|
# scoped_ptr: Scoped Object Ownership
|
|
:toc:
|
|
:toc-title:
|
|
:idprefix: scoped_ptr_
|
|
|
|
## Description
|
|
|
|
The `scoped_ptr` class template stores a pointer to a dynamically allocated object.
|
|
(Dynamically allocated objects are allocated with the {cpp} `new` expression.) The
|
|
object pointed to is guaranteed to be deleted, either on destruction of the `scoped_ptr`,
|
|
or via an explicit `reset`. See the <<scoped_ptr_example,example>>.
|
|
|
|
`scoped_ptr` is a simple solution for simple needs. It supplies a basic "resource acquisition
|
|
is initialization" facility, without shared-ownership or transfer-of-ownership semantics.
|
|
Both its name and enforcement of semantics (by being noncopyable) signal its intent to retain
|
|
ownership solely within the current scope. Because it is noncopyable, it is safer than `shared_ptr`
|
|
for pointers which should not be copied.
|
|
|
|
Because `scoped_ptr` is simple, in its usual implementation every operation is as fast as for a
|
|
built-in pointer and it has no more space overhead that a built-in pointer.
|
|
|
|
`scoped_ptr` cannot be used in {cpp} Standard Library containers. Use `shared_ptr` or `std::unique_ptr`
|
|
if you need a smart pointer that can.
|
|
|
|
`scoped_ptr` cannot correctly hold a pointer to a dynamically allocated array. See `scoped_array` for that usage.
|
|
|
|
The class template is parameterized on `T`, the type of the object pointed to. Destroying `T` must not thow exceptions,
|
|
and `T` must be complete at the point `scoped_ptr<T>::~scoped_ptr` is instantiated.
|
|
|
|
## Synopsis
|
|
|
|
`scoped_ptr` is defined in `<boost/smart_ptr/scoped_ptr.hpp>`.
|
|
|
|
```
|
|
namespace boost {
|
|
|
|
template<class T> class scoped_ptr {
|
|
private:
|
|
|
|
scoped_ptr(scoped_ptr const&);
|
|
scoped_ptr& operator=(scoped_ptr const&);
|
|
|
|
void operator==(scoped_ptr const&) const;
|
|
void operator!=(scoped_ptr const&) const;
|
|
|
|
public:
|
|
|
|
typedef T element_type;
|
|
|
|
explicit scoped_ptr(T * p = 0) noexcept;
|
|
~scoped_ptr() noexcept;
|
|
|
|
void reset(T * p = 0) noexcept;
|
|
|
|
T & operator*() const noexcept;
|
|
T * operator->() const noexcept;
|
|
T * get() const noexcept;
|
|
|
|
explicit operator bool() const noexcept;
|
|
|
|
void swap(scoped_ptr & b) noexcept;
|
|
};
|
|
|
|
template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) noexcept;
|
|
|
|
template<class T>
|
|
bool operator==( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
|
|
template<class T>
|
|
bool operator==( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
|
|
|
|
template<class T>
|
|
bool operator!=( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
|
|
template<class T>
|
|
bool operator!=( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
|
|
}
|
|
```
|
|
|
|
## Members
|
|
|
|
### element_type
|
|
|
|
typedef T element_type;
|
|
|
|
Provides the type of the stored pointer.
|
|
|
|
### constructor
|
|
|
|
explicit scoped_ptr(T * p = 0) noexcept;
|
|
|
|
Constructs a `scoped_ptr`, storing a copy of `p`, which must have been allocated via a
|
|
{cpp} `new` expression or be 0. `T` is not required be a complete type.
|
|
|
|
### destructor
|
|
|
|
~scoped_ptr() noexcept;
|
|
|
|
Destroys the object pointed to by the stored pointer, if any, as if by using
|
|
`delete this\->get()`. `T` must be a complete type.
|
|
|
|
### reset
|
|
|
|
void reset(T * p = 0) noexcept;
|
|
|
|
Deletes the object pointed to by the stored pointer and then stores a copy of
|
|
`p`, which must have been allocated via a {cpp} `new` expression or be 0.
|
|
|
|
Since the previous object needs to be deleted, `T` must be a complete type.
|
|
|
|
### indirection
|
|
|
|
T & operator*() const noexcept;
|
|
|
|
Returns a reference to the object pointed to by the stored pointer. Behavior is undefined if the stored pointer is 0.
|
|
|
|
T * operator->() const noexcept;
|
|
|
|
Returns the stored pointer. Behavior is undefined if the stored pointer is 0.
|
|
|
|
### get
|
|
|
|
T * get() const noexcept;
|
|
|
|
Returns the stored pointer. `T` need not be a complete type.
|
|
|
|
### conversions
|
|
|
|
explicit operator bool () const noexcept; // never throws
|
|
|
|
Returns `get() != 0`.
|
|
|
|
NOTE: On C++03 compilers, the return value is of an unspecified type.
|
|
|
|
### swap
|
|
|
|
void swap(scoped_ptr & b) noexcept;
|
|
|
|
Exchanges the contents of the two smart pointers. `T` need not be a complete type.
|
|
|
|
## Free Functions
|
|
|
|
### swap
|
|
|
|
template<class T> void swap(scoped_ptr<T> & a, scoped_ptr<T> & b) noexcept;
|
|
|
|
Equivalent to `a.swap(b)`.
|
|
|
|
### comparisons
|
|
|
|
template<class T> bool operator==( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
|
|
|
|
template<class T> bool operator==( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
|
|
|
|
Returns `p.get() == nullptr`.
|
|
|
|
template<class T> bool operator!=( scoped_ptr<T> const & p, std::nullptr_t ) noexcept;
|
|
|
|
template<class T> bool operator!=( std::nullptr_t, scoped_ptr<T> const & p ) noexcept;
|
|
|
|
Returns `p.get() != nullptr`.
|
|
|
|
## Example
|
|
|
|
Here's an example that uses `scoped_ptr`.
|
|
|
|
```
|
|
#include <boost/scoped_ptr.hpp>
|
|
#include <iostream>
|
|
|
|
struct Shoe { ~Shoe() { std::cout << "Buckle my shoe\n"; } };
|
|
|
|
class MyClass {
|
|
boost::scoped_ptr<int> ptr;
|
|
public:
|
|
MyClass() : ptr(new int) { *ptr = 0; }
|
|
int add_one() { return ++*ptr; }
|
|
};
|
|
|
|
int main()
|
|
{
|
|
boost::scoped_ptr<Shoe> x(new Shoe);
|
|
MyClass my_instance;
|
|
std::cout << my_instance.add_one() << '\n';
|
|
std::cout << my_instance.add_one() << '\n';
|
|
}
|
|
```
|
|
|
|
The example program produces the beginning of a child's nursery rhyme:
|
|
|
|
```
|
|
1
|
|
2
|
|
Buckle my shoe
|
|
```
|
|
|
|
## Rationale
|
|
|
|
The primary reason to use `scoped_ptr` rather than `std::auto_ptr` or `std::unique_ptr` is to let readers of your code
|
|
know that you intend "resource acquisition is initialization" to be applied only for the current scope, and have no intent to transfer ownership.
|
|
|
|
A secondary reason to use `scoped_ptr` is to prevent a later maintenance programmer from adding a function that transfers
|
|
ownership by returning the `auto_ptr`, because the maintenance programmer saw `auto_ptr`, and assumed ownership could safely be transferred.
|
|
|
|
Think of `bool` vs `int`. We all know that under the covers `bool` is usually just an `int`. Indeed, some argued against including bool in the {cpp}
|
|
standard because of that. But by coding `bool` rather than `int`, you tell your readers what your intent is. Same with `scoped_ptr`; by using it you are signaling intent.
|
|
|
|
It has been suggested that `scoped_ptr<T>` is equivalent to `std::auto_ptr<T> const`. Ed Brey pointed out, however, that `reset` will not work on a `std::auto_ptr<T> const`.
|
|
|
|
## Handle/Body Idiom
|
|
|
|
One common usage of `scoped_ptr` is to implement a handle/body (also called pimpl) idiom which avoids exposing the body (implementation) in the header file.
|
|
|
|
The `link:../../example/scoped_ptr_example_test.cpp[scoped_ptr_example_test.cpp]` sample program includes a header file,
|
|
`link:../../example/scoped_ptr_example.hpp[scoped_ptr_example.hpp]`, which uses a `scoped_ptr<>` to an incomplete type to hide the
|
|
implementation. The instantiation of member functions which require a complete type occurs in the `link:../../example/scoped_ptr_example.cpp[scoped_ptr_example.cpp]`
|
|
implementation file.
|
|
|
|
## Frequently Asked Questions
|
|
|
|
[qanda]
|
|
Why doesn't `scoped_ptr` have a `release()` member?::
|
|
|
|
When reading source code, it is valuable to be able to draw conclusions about program behavior based on the types being used. If `scoped_ptr` had a `release()` member,
|
|
it would become possible to transfer ownership of the held pointer, weakening its role as a way of limiting resource lifetime to a given context. Use `std::auto_ptr` where
|
|
transfer of ownership is required. (supplied by Dave Abrahams)
|