RValueReferenceWrapper.h 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <cassert>
  18. #include <memory>
  19. #include <utility>
  20. namespace folly {
  21. /**
  22. * Class template that wraps a reference to an rvalue. Similar to
  23. * std::reference_wrapper but with three important differences:
  24. *
  25. * 1) folly::rvalue_reference_wrappers can only be moved, not copied;
  26. * 2) the get() function and the conversion-to-T operator are destructive and
  27. * not const, they invalidate the wrapper;
  28. * 3) the constructor-from-T is explicit.
  29. *
  30. * These restrictions are designed to make it harder to accidentally create a
  31. * a dangling rvalue reference, or to use an rvalue reference multiple times.
  32. * (Using an rvalue reference typically implies invalidation of the target
  33. * object, such as move-assignment to another object.)
  34. *
  35. * @seealso folly::rref
  36. */
  37. template <class T>
  38. class rvalue_reference_wrapper {
  39. public:
  40. using type = T;
  41. /**
  42. * Default constructor. Creates an invalid reference. Must be move-assigned
  43. * to in order to be come valid.
  44. */
  45. rvalue_reference_wrapper() noexcept : ptr_(nullptr) {}
  46. /**
  47. * Explicit constructor to make it harder to accidentally create a dangling
  48. * reference to a temporary.
  49. */
  50. explicit rvalue_reference_wrapper(T&& ref) noexcept
  51. : ptr_(std::addressof(ref)) {}
  52. /**
  53. * No construction from lvalue reference. Use std::move.
  54. */
  55. explicit rvalue_reference_wrapper(T&) noexcept = delete;
  56. /**
  57. * Destructive move construction.
  58. */
  59. rvalue_reference_wrapper(rvalue_reference_wrapper<T>&& other) noexcept
  60. : ptr_(other.ptr_) {
  61. other.ptr_ = nullptr;
  62. }
  63. /**
  64. * Destructive move assignment.
  65. */
  66. rvalue_reference_wrapper& operator=(
  67. rvalue_reference_wrapper&& other) noexcept {
  68. ptr_ = other.ptr_;
  69. other.ptr_ = nullptr;
  70. return *this;
  71. }
  72. /**
  73. * Implicit conversion to raw reference. Destructive.
  74. */
  75. /* implicit */ operator T &&() && noexcept {
  76. return static_cast<rvalue_reference_wrapper&&>(*this).get();
  77. }
  78. /**
  79. * Explicit unwrap. Destructive.
  80. */
  81. T&& get() && noexcept {
  82. assert(valid());
  83. T& ref = *ptr_;
  84. ptr_ = nullptr;
  85. return static_cast<T&&>(ref);
  86. }
  87. /**
  88. * Calls the callable object to whom reference is stored. Only available if
  89. * the wrapped reference points to a callable object. Destructive.
  90. */
  91. template <class... Args>
  92. decltype(auto) operator()(Args&&... args) &&
  93. noexcept(noexcept(std::declval<T>()(std::forward<Args>(args)...))) {
  94. return static_cast<rvalue_reference_wrapper&&>(*this).get()(
  95. std::forward<Args>(args)...);
  96. }
  97. /**
  98. * Check whether wrapped reference is valid.
  99. */
  100. bool valid() const noexcept {
  101. return ptr_ != nullptr;
  102. }
  103. private:
  104. // Disallow copy construction and copy assignment, to make it harder to
  105. // accidentally use an rvalue reference multiple times.
  106. rvalue_reference_wrapper(const rvalue_reference_wrapper&) = delete;
  107. rvalue_reference_wrapper& operator=(const rvalue_reference_wrapper&) = delete;
  108. T* ptr_;
  109. };
  110. /**
  111. * Create a folly::rvalue_reference_wrapper. Analogous to std::ref().
  112. *
  113. * Warning: folly::rvalue_reference_wrappers are potentially dangerous, because
  114. * they can easily be used to capture references to temporary values. Users must
  115. * ensure that the target object outlives the reference wrapper.
  116. *
  117. * @example
  118. * class Object {};
  119. * void f(Object&&);
  120. * // BAD
  121. * void g() {
  122. * auto ref = folly::rref(Object{}); // create reference to temporary
  123. * f(std::move(ref)); // pass dangling reference
  124. * }
  125. * // GOOD
  126. * void h() {
  127. * Object o;
  128. * auto ref = folly::rref(std::move(o));
  129. * f(std::move(ref));
  130. * }
  131. */
  132. template <typename T>
  133. rvalue_reference_wrapper<T> rref(T&& value) noexcept {
  134. return rvalue_reference_wrapper<T>(std::move(value));
  135. }
  136. template <typename T>
  137. rvalue_reference_wrapper<T> rref(T&) noexcept = delete;
  138. } // namespace folly