| //// |
| 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) |