Drake
copyable_unique_ptr.h
Go to the documentation of this file.
1 #pragma once
2 
3 /* Portions copyright (c) 2015 Stanford University and the Authors.
4  Authors: Michael Sherman
5 
6 Licensed under the Apache License, Version 2.0 (the "License"); you may
7 not use this file except in compliance with the License. You may obtain a
8 copy of the License at http://www.apache.org/licenses/LICENSE-2.0.
9 
10 (Adapted from Simbody's ClonePtr class.)
11  */
12 
13 #include <cstddef>
14 #include <iostream>
15 #include <memory>
16 #include <utility>
17 
18 #include "drake/common/drake_assert.h"
19 #include "drake/common/is_cloneable.h"
20 
21 namespace drake {
22 
23 /** @cond */
24 
25 namespace copyable_unique_ptr_detail {
26 
27 // This uses SFINAE to classify a particular class as "copyable". There are two
28 // overloads of the `is_copyable_unique_ptr_compatible_helper` struct: one is
29 // the default implementation and the other relies on the SFINAE and copyable
30 // test.
31 //
32 // The default overload reports that a class is _not_ copyable. Only if the
33 // class being queried passes the copyable test, will the second overload get
34 // created. It defines value to be true. The second overload is a more specific
35 // match to the helper invocation, so, if it exists, it will be instantiated by
36 // preference and report a true value.
37 
38 template <typename V, class>
39 struct is_copyable_unique_ptr_compatible_helper : std::false_type {};
40 
41 // This is the specific overload. The copyable condition is that it is
42 // "cloneable" or has a copy constructor.
43 template <typename V>
44 struct is_copyable_unique_ptr_compatible_helper<
45  V, typename std::enable_if<is_cloneable<V>::value ||
46  std::is_copy_constructible<V>::value>::type>
47  : std::true_type {};
48 
49 
50 } // namespace copyable_unique_ptr_detail
51 /** @endcond */
52 
53 /**
54  Test for determining if an arbitrary class is compatible with the
55  copyable_unique_ptr. For a class to be compatible with the copy_unique_ptr,
56  it must be copy constructible or "cloneable" (see @ref is_cloneable_doc
57  "is_cloneable"). Usage:
58 
59  @code
60  is_copyable_unique_ptr_compatible<TestClass>::value
61  @endcode
62 
63  Evaluates to true if compatible, false otherwise. This can be used in run-time
64  test, `static_assert`s, and in SFINAE voodoo.
65 
66  @see copyable_unique_ptr
67  @see is_cloneable
68  */
69 template <typename T>
71  copyable_unique_ptr_detail::is_copyable_unique_ptr_compatible_helper<T,
72  void>;
73 
74 /** A smart pointer with deep copy semantics.
75 
76  This is _similar_ to `std::unique_ptr` in that it does not permit shared
77  ownership of the contained object. However, unlike `std::unique_ptr`,
78  %copyable_unique_ptr supports copy and assignment operations, by insisting that
79  the contained object be "copyable".
80  To be copyable, the class must have either a public copy constructor, or it
81  must be "cloneable" (see @ref is_cloneable_doc "is_cloneable" for definition).
82  A class can be tested for compatibility using the
83  @ref is_copyable_unique_ptr_compatible struct.
84 
85  Generally, the API is modeled as closely as possible on the C++ standard
86  `std::unique_ptr` API and %copyable_unique_ptr<T> is interoperable with
87  `unique_ptr<T>` wherever that makes sense. However, there are some differences:
88  1. It always uses a default deleter.
89  2. There is no array version.
90  3. To allow for future copy-on-write optimizations, there is a distinction
91  between writable and const access, the get() method is modified to return
92  only a const pointer, with get_mutable() added to return a writable pointer.
93 
94  This class is entirely inline and has no computational or
95  space overhead except when copying is required; it contains just a single
96  pointer and does no reference counting.
97 
98  __Usage__
99 
100  In the simplest use case, the instantiation type will match the type of object
101  it references, e.g.:
102  @code
103  copyable_unique_ptr<Foo> ptr = make_unique<Foo>(...);
104  @endcode
105  In this case, as long `Foo` is deemed compatible, the behavior will be as
106  expected, i.e., when `ptr` copies, it will contain a reference to a new
107  instance of `Foo`.
108 
109  %copyable_unique_ptr can also be used with polymorphic classes -- a
110  %copyable_unique_ptr, instantiated on a _base_ class, references an
111  instance of a _derived_ class. When copying the object, we would want the copy
112  to likewise contain an instance of the derived class. For example:
113 
114  @code
115  copyable_unique_ptr<Base> cu_ptr = make_unique<Derived>();
116  copyable_unique_ptr<Base> other_cu_ptr = cu_ptr; // Triggers a copy.
117  is_dynamic_castable<Derived>(cu_other_ptr.get()); // Should be true.
118  @endcode
119 
120  This works for well-designed polymorphic classes.
121 
122  @warning Ill-formed polymorphic classes can lead to fatal type slicing of the
123  referenced object, such that the new copy contains an instance of `Base`
124  instead of `Derived`. Some mistakes that would lead to this degenerate
125  behavior:
126  - The `Base` class has a public copy constructor.
127  - The `Base` class's Clone() implementation does not invoke the `Derived`
128  class's implementation of a suitable virtual method.
129 
130  @warning One important difference between unique_ptr and %copyable_unique_ptr
131  is that a unique_ptr can be declared on a forward-declared class type. The
132  %copyable_unique_ptr _cannot_. The class must be fully defined so that the
133  %copyable_unique_ptr is able to determine if the type meets the requirements
134  (i.e., public copy constructible or cloneable).
135 
136  <!--
137  For future developers:
138  - the copyability of a base class does *not* imply anything about the
139  copyability of a derived class. In other words, `copyable_unique_ptr<Base>`
140  can be compilable while `copyable_unique_ptr<Derived>` is not.
141  - Given the pointer `copyable_unique_ptr<Base> ptr(new Derived())`, even if
142  this copies "correctly" (such that the copy contains an instance of
143  `Derived`), this does _not_ imply that `copyable_unique_ptr<Derived>` is
144  compilable.
145  -->
146 
147  @see is_copyable_unique_ptr_compatible
148  @tparam T The type of the contained object, which *must* be
149  @ref is_copyable_unique_ptr_compatible "compatibly copyable". May
150  be an abstract or concrete type.
151  */
152 // TODO(SeanCurtis-TRI): Consider extending this to add the Deleter as well.
153 template <typename T>
154 class copyable_unique_ptr : public std::unique_ptr<T> {
156  "copyable_unique_ptr can only be used with a 'copyable' class"
157  ", requiring either a public copy constructor or a valid "
158  "clone method of the form: `unique_ptr<T> Clone() const`.");
159 
160  public:
161  /** @name Constructors **/
162  /**@{*/
163 
164  /** Default constructor stores a `nullptr`. No heap allocation is performed.
165  The empty() method will return true when called on a default-constructed
166  %copyable_unique_ptr. */
167  copyable_unique_ptr() noexcept : std::unique_ptr<T>() {}
168 
169  /** Given a pointer to a writable heap-allocated object, take over
170  ownership of that object. No copying occurs. */
171  explicit copyable_unique_ptr(T* ptr) noexcept : std::unique_ptr<T>(ptr) {}
172 
173  /** Copy constructor is deep; the new %copyable_unique_ptr object contains a
174  new copy of the object in the source, created via the source object's
175  copy constructor or `Clone()` method. If the source container is empty this
176  one will be empty also. */
178  : std::unique_ptr<T>(CopyOrNull(cu_ptr.get())) {}
179 
180  /** Copy constructor from a standard `unique_ptr` of _compatible_ type. The
181  copy is deep; the new %copyable_unique_ptr object contains a new copy of the
182  object in the source, created via the source object's copy constructor or
183  `Clone()` method. If the source container is empty this one will be empty
184  also. */
185  template <typename U>
186  explicit copyable_unique_ptr(const std::unique_ptr<U>& u_ptr)
187  : std::unique_ptr<T>(CopyOrNull(u_ptr.get())) {}
188 
189  /** Move constructor is very fast and leaves the source empty. Ownership
190  is transferred from the source to the new %copyable_unique_ptr. If the source
191  was empty this one will be empty also. No heap activity occurs. */
193  : std::unique_ptr<T>(cu_ptr.release()) {}
194 
195  /** Move constructor from a standard `unique_ptr`. The move is very fast and
196  leaves the source empty. Ownership is transferred from the source to the new
197  %copyable_unique_ptr. If the source was empty this one will be empty also. No
198  heap activity occurs. */
199  explicit copyable_unique_ptr(std::unique_ptr<T>&& u_ptr) noexcept
200  : std::unique_ptr<T>(u_ptr.release()) {}
201 
202  /** Move construction from a compatible standard `unique_ptr`. Type `U*` must
203  be implicitly convertible to type `T*`. Ownership is transferred from the
204  source to the new %copyable_unique_ptr. If the source was empty this one will
205  be empty also. No heap activity occurs. */
206  template <typename U>
207  explicit copyable_unique_ptr(std::unique_ptr<U>&& u_ptr) noexcept
208  : std::unique_ptr<T>(u_ptr.release()) {}
209 
210  /**@}*/
211 
212  /** @name Assignment */
213  /**@{*/
214 
215  /** This form of assignment replaces the currently-held object by
216  the given source object and takes over ownership of the source object. The
217  currently-held object (if any) is deleted. */
218  copyable_unique_ptr& operator=(T* ptr) noexcept {
219  std::unique_ptr<T>::reset(ptr);
220  return *this;
221  }
222 
223  /** This form of assignment replaces the currently-held object by a
224  heap-allocated copy of the source object, created using its copy
225  constructor or `Clone()` method. The currently-held object (if any) is
226  deleted. */
227  copyable_unique_ptr & operator=(const T& ref) {
228  std::unique_ptr<T>::reset(CopyOrNull(&ref));
229  return *this;
230  }
231 
232  /** Copy assignment from %copyable_unique_ptr replaces the currently-held
233  object by a copy of the object held in the source container, created using
234  the source object's copy constructor or `Clone()` method. The currently-held
235  object (if any) is deleted. If the source container is empty this one will be
236  empty also after the assignment. Nothing happens if the source and
237  destination are the same container. */
239  return operator=(static_cast<const std::unique_ptr<T>&>(cu_ptr));
240  }
241 
242  /** Copy assignment from a compatible %copyable_unique_ptr replaces the
243  currently-held object by a copy of the object held in the source container,
244  created using the source object's copy constructor or `Clone()` method. The
245  currently-held object (if any) is deleted. If the source container is empty
246  this one will be empty also after the assignment. Nothing happens if the
247  source and destination are the same container. */
248  template <typename U>
250  return operator=(static_cast<const std::unique_ptr<U>&>(cu_ptr));
251  }
252 
253  /** Copy assignment from a standard `unique_ptr` replaces the
254  currently-held object by a copy of the object held in the source container,
255  created using the source object's copy constructor or `Clone()` method. The
256  currently-held object (if any) is deleted. If the source container is empty
257  this one will be empty also after the assignment. Nothing happens if the
258  source and destination are the same container. */
259  copyable_unique_ptr& operator=(const std::unique_ptr<T>& src) {
260  if (&src != this) {
261  // can't be same ptr unless null
262  DRAKE_DEMAND((get() != src.get()) || !get());
263  std::unique_ptr<T>::reset(CopyOrNull(src.get()));
264  }
265  return *this;
266  }
267 
268  /** Copy assignment from a compatible standard `unique_ptr` replaces the
269  currently-held object by a copy of the object held in the source container,
270  created using the source object's copy constructor or `Clone()` method. The
271  currently-held object (if any) is deleted. If the source container is empty
272  this one will be empty also after the assignment. Nothing happens if the
273  source and destination are the same container. */
274  template <typename U>
275  copyable_unique_ptr& operator=(const std::unique_ptr<U>& u_ptr) {
276  // can't be same ptr unless null
277  DRAKE_DEMAND((get() != u_ptr.get()) || !get());
278  std::unique_ptr<T>::reset(CopyOrNull(u_ptr.get()));
279  return *this;
280  }
281 
282  /** Move assignment replaces the currently-held object by the source object,
283  leaving the source empty. The currently-held object (if any) is deleted.
284  The instance is _not_ copied. Nothing happens if the source and destination
285  are the same containers. */
287  std::unique_ptr<T>::reset(cu_ptr.release());
288  return *this;
289  }
290 
291  /** Move assignment replaces the currently-held object by the compatible
292  source object, leaving the source empty. The currently-held object (if any)
293  is deleted. The instance is _not_ copied. Nothing happens if the source and
294  destination are the same containers. */
295  template <typename U>
297  std::unique_ptr<T>::reset(cu_ptr.release());
298  return *this;
299  }
300 
301  /** Move assignment replaces the currently-held object by the source object,
302  leaving the source empty. The currently-held object (if any) is deleted.
303  The instance is _not_ copied. Nothing happens if the source and destination
304  are the same containers. */
305  copyable_unique_ptr& operator=(std::unique_ptr<T>&& u_ptr) noexcept {
306  std::unique_ptr<T>::reset(u_ptr.release());
307  return *this;
308  }
309 
310  /** Move assignment replaces the currently-held object by the compatible
311  source object, leaving the source empty. The currently-held object (if
312  any) is deleted. The instance is _not_ copied. Nothing happens if the source
313  and destination are the same containers. */
314  template <typename U>
315  copyable_unique_ptr& operator=(std::unique_ptr<U>&& u_ptr) noexcept {
316  std::unique_ptr<T>::reset(u_ptr.release());
317  return *this;
318  }
319 
320  /**@}*/
321 
322  /** @name Observers */
323  /**@{*/
324 
325  /** Return true if this container is empty, which is the state the container
326  is in immediately after default construction and various other
327  operations. */
328  bool empty() const noexcept { return !(*this); }
329 
330  /** Return a const pointer to the contained object if any, or `nullptr`.
331  Note that this is different than `%get()` for the standard smart pointers
332  like `std::unique_ptr` which return a writable pointer. Use get_mutable()
333  here for that purpose. */
334  const T* get() const noexcept { return std::unique_ptr<T>::get(); }
335 
336  /** Return a writable pointer to the contained object if any, or `nullptr`.
337  Note that you need write access to this container in order to get write
338  access to the object it contains.
339 
340  @warning If %copyable_unique_ptr is instantiated on a const template
341  parameter (e.g., `copyable_unique_ptr<const Foo>`), then get_mutable()
342  returns a const pointer. */
343  T* get_mutable() noexcept { return std::unique_ptr<T>::get(); }
344 
345  /**@}*/
346 
347  private:
348  // Selects Clone iff there is no copy constructor and the Clone method is of
349  // the expected form.
350  template <typename U>
351  static typename std::enable_if<
353  CopyOrNullHelper(const U* ptr, int) {
354  return ptr->Clone().release();
355  }
356 
357  // Default to copy constructor if present.
358  template <typename U>
359  static
360  U* CopyOrNullHelper(const U* ptr, ...) {
361  return new U(*ptr);
362  }
363 
364  // If src is non-null, clone it; otherwise return nullptr.
365  static T* CopyOrNull(const T *ptr) {
366  return ptr ? CopyOrNullHelper(ptr, 1) : nullptr;
367  }
368 };
369 
370 /** Output the system-dependent representation of the pointer contained
371  in a copyable_unique_ptr object. This is equivalent to `os << p.get();`.
372  @relates copyable_unique_ptr */
373 template <class charT, class traits, class T>
374 inline std::basic_ostream<charT, traits>& operator<<(
375  std::basic_ostream<charT, traits>& os,
376  const copyable_unique_ptr<T>& cu_ptr) {
377  os << cu_ptr.get();
378  return os;
379 }
380 
381 } // namespace drake
copyable_unique_ptr_detail::is_copyable_unique_ptr_compatible_helper< T, void > is_copyable_unique_ptr_compatible
Test for determining if an arbitrary class is compatible with the copyable_unique_ptr.
Definition: copyable_unique_ptr.h:72
is_cloneable_detail::is_cloneable_helper< T, void > is_cloneable
Definition: is_cloneable.h:78
YAML::Node get(const YAML::Node &parent, const std::string &key)
Definition: yaml_util.cc:61
copyable_unique_ptr & operator=(std::unique_ptr< T > &&u_ptr) noexcept
Move assignment replaces the currently-held object by the source object, leaving the source empty...
Definition: copyable_unique_ptr.h:305
copyable_unique_ptr() noexcept
Default constructor stores a nullptr.
Definition: copyable_unique_ptr.h:167
copyable_unique_ptr(T *ptr) noexcept
Given a pointer to a writable heap-allocated object, take over ownership of that object.
Definition: copyable_unique_ptr.h:171
Definition: automotive_demo.cc:89
copyable_unique_ptr & operator=(T *ptr) noexcept
This form of assignment replaces the currently-held object by the given source object and takes over ...
Definition: copyable_unique_ptr.h:218
STL namespace.
copyable_unique_ptr(std::unique_ptr< U > &&u_ptr) noexcept
Move construction from a compatible standard unique_ptr.
Definition: copyable_unique_ptr.h:207
copyable_unique_ptr & operator=(const std::unique_ptr< T > &src)
Copy assignment from a standard unique_ptr replaces the currently-held object by a copy of the object...
Definition: copyable_unique_ptr.h:259
copyable_unique_ptr & operator=(const copyable_unique_ptr< U > &cu_ptr)
Copy assignment from a compatible copyable_unique_ptr replaces the currently-held object by a copy of...
Definition: copyable_unique_ptr.h:249
int value
Definition: copyable_unique_ptr_test.cc:61
std::ostream & operator<<(std::ostream &out, const LaneEnd::Which &which_end)
Streams a string representation of which_end into out.
Definition: lane_data.cc:11
#define DRAKE_DEMAND(condition)
Evaluates condition and iff the value is false will trigger an assertion failure with a message showi...
Definition: drake_assert.h:45
copyable_unique_ptr & operator=(const copyable_unique_ptr &cu_ptr)
Copy assignment from copyable_unique_ptr replaces the currently-held object by a copy of the object h...
Definition: copyable_unique_ptr.h:238
copyable_unique_ptr & operator=(copyable_unique_ptr &&cu_ptr) noexcept
Move assignment replaces the currently-held object by the source object, leaving the source empty...
Definition: copyable_unique_ptr.h:286
copyable_unique_ptr(copyable_unique_ptr &&cu_ptr) noexcept
Move constructor is very fast and leaves the source empty.
Definition: copyable_unique_ptr.h:192
copyable_unique_ptr & operator=(const T &ref)
This form of assignment replaces the currently-held object by a heap-allocated copy of the source obj...
Definition: copyable_unique_ptr.h:227
copyable_unique_ptr & operator=(std::unique_ptr< U > &&u_ptr) noexcept
Move assignment replaces the currently-held object by the compatible source object, leaving the source empty.
Definition: copyable_unique_ptr.h:315
const T * get() const noexcept
Return a const pointer to the contained object if any, or nullptr.
Definition: copyable_unique_ptr.h:334
copyable_unique_ptr & operator=(const std::unique_ptr< U > &u_ptr)
Copy assignment from a compatible standard unique_ptr replaces the currently-held object by a copy of...
Definition: copyable_unique_ptr.h:275
bool empty() const noexcept
Return true if this container is empty, which is the state the container is in immediately after defa...
Definition: copyable_unique_ptr.h:328
copyable_unique_ptr(std::unique_ptr< T > &&u_ptr) noexcept
Move constructor from a standard unique_ptr.
Definition: copyable_unique_ptr.h:199
T * get_mutable() noexcept
Return a writable pointer to the contained object if any, or nullptr.
Definition: copyable_unique_ptr.h:343
copyable_unique_ptr(const std::unique_ptr< U > &u_ptr)
Copy constructor from a standard unique_ptr of compatible type.
Definition: copyable_unique_ptr.h:186
copyable_unique_ptr(const copyable_unique_ptr &cu_ptr)
Copy constructor is deep; the new copyable_unique_ptr object contains a new copy of the object in the...
Definition: copyable_unique_ptr.h:177
copyable_unique_ptr & operator=(copyable_unique_ptr< U > &&cu_ptr) noexcept
Move assignment replaces the currently-held object by the compatible source object, leaving the source empty.
Definition: copyable_unique_ptr.h:296
A smart pointer with deep copy semantics.
Definition: copyable_unique_ptr.h:154