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 
20 namespace drake {
21 
22 /** A smart pointer with deep copy semantics.
23 
24  This is _similar_ to `std::unique_ptr` in that it does not permit shared
25  ownership of the contained object. However, unlike `std::unique_ptr`,
26  %copyable_unique_ptr supports copy and assignment operations, by insisting that
27  the contained object be "copyable". To be copyable, the class must have either
28  an accessible copy constructor, or it must have an accessible clone method
29  with signature @code
30  std::unique_ptr<Foo> Clone() const;
31  @endcode
32  where Foo is the type of the managed object. By "accessible" we mean either
33  that the copy constructor or clone method is public, or
34  `friend copyable_unique_ptr<Foo>;` appears in Foo's class declaration.
35 
36  <!-- Developer note: if you change or extend the definition of an acceptable
37  clone method here, be sure to consider whether drake::is_cloneable should
38  be changed as well. -->
39 
40  Generally, the API is modeled as closely as possible on the C++ standard
41  `std::unique_ptr` API and %copyable_unique_ptr<T> is interoperable with
42  `unique_ptr<T>` wherever that makes sense. However, there are some differences:
43  1. It always uses a default deleter.
44  2. There is no array version.
45  3. To allow for future copy-on-write optimizations, there is a distinction
46  between writable and const access, the get() method is modified to return
47  only a const pointer, with get_mutable() added to return a writable pointer.
48 
49  This class is entirely inline and has no computational or space overhead except
50  when copying is required; it contains just a single pointer and does no
51  reference counting.
52 
53  __Usage__
54 
55  In the simplest use case, the instantiation type will match the type of object
56  it references, e.g.:
57  @code
58  copyable_unique_ptr<Foo> ptr = make_unique<Foo>(...);
59  @endcode
60  In this case, as long `Foo` is deemed compatible, the behavior will be as
61  expected, i.e., when `ptr` copies, it will contain a reference to a new
62  instance of `Foo`.
63 
64  %copyable_unique_ptr can also be used with polymorphic classes -- a
65  %copyable_unique_ptr, instantiated on a _base_ class, references an
66  instance of a _derived_ class. When copying the object, we would want the copy
67  to likewise contain an instance of the derived class. For example:
68 
69  @code
70  copyable_unique_ptr<Base> cu_ptr = make_unique<Derived>();
71  copyable_unique_ptr<Base> other_cu_ptr = cu_ptr; // Triggers a copy.
72  is_dynamic_castable<Derived>(cu_other_ptr.get()); // Should be true.
73  @endcode
74 
75  This works for well-designed polymorphic classes.
76 
77  @warning Ill-formed polymorphic classes can lead to fatal type slicing of the
78  referenced object, such that the new copy contains an instance of `Base`
79  instead of `Derived`. Some mistakes that would lead to this degenerate
80  behavior:
81  - The `Base` class has a public copy constructor.
82  - The `Base` class's Clone() implementation does not invoke the `Derived`
83  class's implementation of a suitable virtual method.
84 
85  @warning One important difference between unique_ptr and %copyable_unique_ptr
86  is that a unique_ptr can be declared on a forward-declared class type. The
87  %copyable_unique_ptr _cannot_. The class must be fully defined so that the
88  %copyable_unique_ptr is able to determine if the type meets the requirements
89  (i.e., public copy constructible or cloneable).
90 
91  <!--
92  For future developers:
93  - the copyability of a base class does *not* imply anything about the
94  copyability of a derived class. In other words, `copyable_unique_ptr<Base>`
95  can be compilable while `copyable_unique_ptr<Derived>` is not.
96  - Given the pointer `copyable_unique_ptr<Base> ptr(new Derived())`, even if
97  this copies "correctly" (such that the copy contains an instance of
98  `Derived`), this does _not_ imply that `copyable_unique_ptr<Derived>` is
99  compilable.
100  -->
101 
102  @tparam T The type of the contained object, which *must* be copyable as
103  defined above. May be an abstract or concrete type.
104  */
105 // TODO(SeanCurtis-TRI): Consider extending this to add the Deleter as well.
106 template <typename T>
107 class copyable_unique_ptr : public std::unique_ptr<T> {
108  public:
109  /** @name Constructors **/
110  /**@{*/
111 
112  /** Default constructor stores a `nullptr`. No heap allocation is performed.
113  The empty() method will return true when called on a default-constructed
114  %copyable_unique_ptr. */
115  copyable_unique_ptr() noexcept : std::unique_ptr<T>() {}
116 
117  /** Given a pointer to a writable heap-allocated object, take over
118  ownership of that object. No copying occurs. */
119  explicit copyable_unique_ptr(T* ptr) noexcept : std::unique_ptr<T>(ptr) {}
120 
121  /** Copy constructor is deep; the new %copyable_unique_ptr object contains a
122  new copy of the object in the source, created via the source object's
123  copy constructor or `Clone()` method. If the source container is empty this
124  one will be empty also. */
126  : std::unique_ptr<T>(CopyOrNull(cu_ptr.get())) {}
127 
128  /** Copy constructor from a standard `unique_ptr` of _compatible_ type. The
129  copy is deep; the new %copyable_unique_ptr object contains a new copy of the
130  object in the source, created via the source object's copy constructor or
131  `Clone()` method. If the source container is empty this one will be empty
132  also. */
133  template <typename U>
134  explicit copyable_unique_ptr(const std::unique_ptr<U>& u_ptr)
135  : std::unique_ptr<T>(CopyOrNull(u_ptr.get())) {}
136 
137  /** Move constructor is very fast and leaves the source empty. Ownership
138  is transferred from the source to the new %copyable_unique_ptr. If the source
139  was empty this one will be empty also. No heap activity occurs. */
141  : std::unique_ptr<T>(cu_ptr.release()) {}
142 
143  /** Move constructor from a standard `unique_ptr`. The move is very fast and
144  leaves the source empty. Ownership is transferred from the source to the new
145  %copyable_unique_ptr. If the source was empty this one will be empty also. No
146  heap activity occurs. */
147  explicit copyable_unique_ptr(std::unique_ptr<T>&& u_ptr) noexcept
148  : std::unique_ptr<T>(u_ptr.release()) {}
149 
150  /** Move construction from a compatible standard `unique_ptr`. Type `U*` must
151  be implicitly convertible to type `T*`. Ownership is transferred from the
152  source to the new %copyable_unique_ptr. If the source was empty this one will
153  be empty also. No heap activity occurs. */
154  template <typename U>
155  explicit copyable_unique_ptr(std::unique_ptr<U>&& u_ptr) noexcept
156  : std::unique_ptr<T>(u_ptr.release()) {}
157 
158  /**@}*/
159 
160  /** @name Assignment */
161  /**@{*/
162 
163  /** This form of assignment replaces the currently-held object by
164  the given source object and takes over ownership of the source object. The
165  currently-held object (if any) is deleted. */
166  copyable_unique_ptr& operator=(T* ptr) noexcept {
167  std::unique_ptr<T>::reset(ptr);
168  return *this;
169  }
170 
171  /** This form of assignment replaces the currently-held object by a
172  heap-allocated copy of the source object, created using its copy
173  constructor or `Clone()` method. The currently-held object (if any) is
174  deleted. */
175  copyable_unique_ptr & operator=(const T& ref) {
176  std::unique_ptr<T>::reset(CopyOrNull(&ref));
177  return *this;
178  }
179 
180  /** Copy assignment from %copyable_unique_ptr replaces the currently-held
181  object by a copy of the object held in the source container, created using
182  the source object's copy constructor or `Clone()` method. The currently-held
183  object (if any) is deleted. If the source container is empty this one will be
184  empty also after the assignment. Nothing happens if the source and
185  destination are the same container. */
187  return operator=(static_cast<const std::unique_ptr<T>&>(cu_ptr));
188  }
189 
190  /** Copy assignment from a compatible %copyable_unique_ptr replaces the
191  currently-held object by a copy of the object held in the source container,
192  created using the source object's copy constructor or `Clone()` method. The
193  currently-held object (if any) is deleted. If the source container is empty
194  this one will be empty also after the assignment. Nothing happens if the
195  source and destination are the same container. */
196  template <typename U>
198  return operator=(static_cast<const std::unique_ptr<U>&>(cu_ptr));
199  }
200 
201  /** Copy assignment from a standard `unique_ptr` replaces the
202  currently-held object by a copy of the object held in the source container,
203  created using the source object's copy constructor or `Clone()` method. The
204  currently-held object (if any) is deleted. If the source container is empty
205  this one will be empty also after the assignment. Nothing happens if the
206  source and destination are the same container. */
207  copyable_unique_ptr& operator=(const std::unique_ptr<T>& src) {
208  if (&src != this) {
209  // can't be same ptr unless null
210  DRAKE_DEMAND((get() != src.get()) || !get());
211  std::unique_ptr<T>::reset(CopyOrNull(src.get()));
212  }
213  return *this;
214  }
215 
216  /** Copy assignment from a compatible standard `unique_ptr` replaces the
217  currently-held object by a copy of the object held in the source container,
218  created using the source object's copy constructor or `Clone()` method. The
219  currently-held object (if any) is deleted. If the source container is empty
220  this one will be empty also after the assignment. Nothing happens if the
221  source and destination are the same container. */
222  template <typename U>
223  copyable_unique_ptr& operator=(const std::unique_ptr<U>& u_ptr) {
224  // can't be same ptr unless null
225  DRAKE_DEMAND((get() != u_ptr.get()) || !get());
226  std::unique_ptr<T>::reset(CopyOrNull(u_ptr.get()));
227  return *this;
228  }
229 
230  /** Move assignment replaces the currently-held object by the source object,
231  leaving the source empty. The currently-held object (if any) is deleted.
232  The instance is _not_ copied. Nothing happens if the source and destination
233  are the same containers. */
235  std::unique_ptr<T>::reset(cu_ptr.release());
236  return *this;
237  }
238 
239  /** Move assignment replaces the currently-held object by the compatible
240  source object, leaving the source empty. The currently-held object (if any)
241  is deleted. The instance is _not_ copied. Nothing happens if the source and
242  destination are the same containers. */
243  template <typename U>
245  std::unique_ptr<T>::reset(cu_ptr.release());
246  return *this;
247  }
248 
249  /** Move assignment replaces the currently-held object by the source object,
250  leaving the source empty. The currently-held object (if any) is deleted.
251  The instance is _not_ copied. Nothing happens if the source and destination
252  are the same containers. */
253  copyable_unique_ptr& operator=(std::unique_ptr<T>&& u_ptr) noexcept {
254  std::unique_ptr<T>::reset(u_ptr.release());
255  return *this;
256  }
257 
258  /** Move assignment replaces the currently-held object by the compatible
259  source object, leaving the source empty. The currently-held object (if
260  any) is deleted. The instance is _not_ copied. Nothing happens if the source
261  and destination are the same containers. */
262  template <typename U>
263  copyable_unique_ptr& operator=(std::unique_ptr<U>&& u_ptr) noexcept {
264  std::unique_ptr<T>::reset(u_ptr.release());
265  return *this;
266  }
267 
268  /**@}*/
269 
270  /** @name Observers */
271  /**@{*/
272 
273  /** Return true if this container is empty, which is the state the container
274  is in immediately after default construction and various other
275  operations. */
276  bool empty() const noexcept { return !(*this); }
277 
278  /** Return a const pointer to the contained object if any, or `nullptr`.
279  Note that this is different than `%get()` for the standard smart pointers
280  like `std::unique_ptr` which return a writable pointer. Use get_mutable()
281  here for that purpose. */
282  const T* get() const noexcept { return std::unique_ptr<T>::get(); }
283 
284  /** Return a writable pointer to the contained object if any, or `nullptr`.
285  Note that you need write access to this container in order to get write
286  access to the object it contains.
287 
288  @warning If %copyable_unique_ptr is instantiated on a const template
289  parameter (e.g., `copyable_unique_ptr<const Foo>`), then get_mutable()
290  returns a const pointer. */
291  T* get_mutable() noexcept { return std::unique_ptr<T>::get(); }
292 
293  /**@}*/
294  private:
295  // The can_copy() and can_clone() methods must be defined within the
296  // copyable_unique_ptr class so that they have the same method access as
297  // the class does. That way we can use them to determine whether
298  // copyable_unique_ptr can get access. That precludes using helper classes
299  // like drake::is_cloneable because those may have different access due to an
300  // explicit friend declaration giving copyable_unique_ptr<Foo> access to Foo's
301  // private business. The static_assert below ensures that at least one of
302  // these must return true.
303 
304  // SFINAE magic explanation. We're combining several tricks here:
305  // (1) "..." as a parameter type is a last choice; an exact type match is
306  // preferred in overload resolution.
307  // (2) Use a dummy template parameter U that is always just T but defers
308  // instantiation so that substitution failure is not fatal.
309  // (3) We construct a non-evaluated copy constructor and Clone method in
310  // templatized methods to prevent instantiation if the needed method
311  // doesn't exist or isn't accessible. If instantiation is successful,
312  // we produce an exact-match method that trumps the "..."-using method.
313  // (4) Make these constexpr so they can be used in static_assert.
314 
315  // True iff type T provides a copy constructor that is accessible from
316  // %copyable_unique_ptr<T>. Invoke with `can_copy(1)`; the argument is used
317  // to select the right method. Note that if both `can_copy()` and
318  // `can_clone()` return true, we will prefer the copy constructor over the
319  // Clone() method.
320  static constexpr bool can_copy(...) { return false; }
321 
322  // If this instantiates successfully it will be the preferred method called
323  // when an integer argument is provided.
324  template <typename U = T>
325  static constexpr std::enable_if_t<
326  std::is_same<decltype(U(std::declval<const U&>())), U>::value,
327  bool>
328  can_copy(int) {
329  return true;
330  }
331 
332  // True iff type T provides a `Clone()` method with the appropriate
333  // signature (see class documentation) that is accessible from
334  // %copyable_unique_ptr<T>. Invoke with `can_clone(1)`; the argument is used
335  // to select the right method.
336  static constexpr bool can_clone(...) { return false; }
337 
338  // If this instantiates successfully it will be the preferred method called
339  // when an integer argument is provide.
340  template <typename U = T>
341  static constexpr std::enable_if_t<
342  std::is_same<decltype(std::declval<const U>().Clone()),
343  std::unique_ptr<std::remove_const_t<U>>>::value,
344  bool>
345  can_clone(int) {
346  return true;
347  }
348 
349  static_assert(
350  can_copy(1) || can_clone(1),
351  "copyable_unique_ptr<T> can only be used with a 'copyable' class T, "
352  "requiring either a copy constructor or a Clone method of the form "
353  "'unique_ptr<T> Clone() const', accessible to copyable_unique_ptr<T>. "
354  "You may need to friend copyable_unique_ptr<T>.");
355 
356  // Selects Clone iff there is no copy constructor and the Clone method is of
357  // the expected form.
358  template <typename U = T>
359  static typename std::enable_if<!can_copy(1) && can_clone(1), U*>::type
360  CopyOrNullHelper(const U* ptr, int) {
361  return ptr->Clone().release();
362  }
363 
364  // Default to copy constructor if present.
365  template <typename U>
366  static
367  U* CopyOrNullHelper(const U* ptr, ...) {
368  return new U(*ptr);
369  }
370 
371  // If src is non-null, clone it; otherwise return nullptr.
372  static T* CopyOrNull(const T *ptr) {
373  return ptr ? CopyOrNullHelper(ptr, 1) : nullptr;
374  }
375 };
376 
377 /** Output the system-dependent representation of the pointer contained
378  in a copyable_unique_ptr object. This is equivalent to `os << p.get();`.
379  @relates copyable_unique_ptr */
380 template <class charT, class traits, class T>
381 inline std::basic_ostream<charT, traits>& operator<<(
382  std::basic_ostream<charT, traits>& os,
383  const copyable_unique_ptr<T>& cu_ptr) {
384  os << cu_ptr.get();
385  return os;
386 }
387 
388 } // namespace drake
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:253
double value
Definition: wrap_test_util_py.cc:12
copyable_unique_ptr() noexcept
Default constructor stores a nullptr.
Definition: copyable_unique_ptr.h:115
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:119
Definition: automotive_demo.cc:90
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:166
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:155
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:207
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:197
#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:186
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:234
copyable_unique_ptr(copyable_unique_ptr &&cu_ptr) noexcept
Move constructor is very fast and leaves the source empty.
Definition: copyable_unique_ptr.h:140
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:175
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:263
const T * get() const noexcept
Return a const pointer to the contained object if any, or nullptr.
Definition: copyable_unique_ptr.h:282
std::basic_ostream< charT, traits > & operator<<(std::basic_ostream< charT, traits > &os, const copyable_unique_ptr< T > &cu_ptr)
Output the system-dependent representation of the pointer contained in a copyable_unique_ptr object...
Definition: copyable_unique_ptr.h:381
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:223
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:276
copyable_unique_ptr(std::unique_ptr< T > &&u_ptr) noexcept
Move constructor from a standard unique_ptr.
Definition: copyable_unique_ptr.h:147
T * get_mutable() noexcept
Return a writable pointer to the contained object if any, or nullptr.
Definition: copyable_unique_ptr.h:291
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:134
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:125
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:244
A smart pointer with deep copy semantics.
Definition: copyable_unique_ptr.h:107