我猜不是,但我想证实一下。 const Foo&&
是否有用,其中Foo
是类类型?
答案 0 :(得分:65)
它们偶尔会有用。草案C ++ 0x本身在几个地方使用它们,例如:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
以上两个重载确保其他ref(T&)
和cref(const T&)
函数不绑定到rvalues(否则可能)。
<强>更新强>
我刚刚检查了官方标准N3290,遗憾的是它不公开,并且它有20.8个函数对象[function.objects] / p2:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
然后我检查了最新的C ++ 11后草案,它是公开的,N3485,并且在20.8函数对象[function.objects] / p2中它仍然说:
template <class T> void ref(const T&&) = delete;
template <class T> void cref(const T&&) = delete;
答案 1 :(得分:6)
获取 const rvalue引用 (而不是=delete
)的语义是说:
以下用例可能是恕我直言是右值引用const 的好用例,尽管该语言决定不采用这种方法(请参见{{3} }。
通常建议使用make_unique
和make_shared
,但是unique_ptr
和shared_ptr
都可以由原始指针构造。两个构造函数都按值获取指针并将其复制。两者都允许(即:不阻止)继续使用构造函数中传递给它们的原始指针。
以下代码使用 double free 编译并生成结果:
int* ptr = new int(9);
std::unique_ptr<int> p { ptr };
// we forgot that ptr is already being managed
delete ptr;
如果unique_ptr
和shared_ptr
的相关构造函数希望将原始指针作为常量值,例如它们,则可以防止上述情况发生为unique_ptr
:
unique_ptr(T* const&& p) : ptr{p} {}
在这种情况下,上面的 双重免费 代码无法编译,但以下代码可以:
std::unique_ptr<int> p1 { std::move(ptr) }; // more verbose: user moves ownership
std::unique_ptr<int> p2 { new int(7) }; // ok, rvalue
请注意,ptr
在移动后仍可以使用,因此潜在的错误并未完全消失。但是,如果要求用户调用std::move
,则该错误会归入以下常见规则:不要使用已移动的资源。
一个人可以问:好,但是为什么要T*
const && p
?
原因很简单,允许从const指针 创建unique_ptr
。请记住,常量右值引用比右值引用更通用,因为它接受const
和non-const
。因此,我们可以允许以下操作:
int* const ptr = new int(9);
auto p = std::unique_ptr<int> { std::move(ptr) };
如果我们仅希望 rvalue引用(编译错误:无法将 const rvalue 绑定到 rvalue ),则不会成功。
无论如何,现在提出这样的事情为时已晚。但是这个想法确实提出了右值引用const 的合理用法。
答案 2 :(得分:3)
它们是允许的,甚至是基于const
排名的函数,但由于你不能从const Foo&&
引用的const对象移动,它们没用。
答案 3 :(得分:1)
我无法想到这种情况会直接有用,但可以间接使用:
template<class T>
void f(T const &x) {
cout << "lvalue";
}
template<class T>
void f(T &&x) {
cout << "rvalue";
}
template<class T>
void g(T &x) {
f(T());
}
template<class T>
void h(T const &x) {
g(x);
}
g 中的T是T const,所以 f 的x是T const&amp;&amp;。
这很可能会导致 f 中的漫游错误(当它试图移动或使用该对象时),但 f 可能会采用rvalue-ref,以便如果不修改右值,就不能在左值上调用它(如上面的一个简单例子)。
答案 4 :(得分:1)
除了std::ref之外,标准库还出于相同目的在std::as_const中使用const rvalue引用。
template <class T>
void as_const(const T&&) = delete;
在获取包装值时,它还用作std::optional中的返回值:
constexpr const T&& operator*() const&&;
constexpr const T&& value() const &&;
以及std::get:
template <class T, class... Types>
constexpr const T&& get(const std::variant<Types...>&& v);
template< class T, class... Types >
constexpr const T&& get(const tuple<Types...>&& t) noexcept;
大概是为了在访问包装的值时保持值的类别以及包装器的恒定性。
这是否可以在包装的对象上调用const rvalue ref限定的函数有所不同。也就是说,我不知道const rvalue ref限定函数的任何用途。