[英]why is returning rvalue reference wrong
我想知道具有r引用返回类型的地方出了什么问题:
vector<T>&& id2(vector<T>&& v) { return std::move(v);}
如下面的代码。 做a = id2(a)
设置为空。 返回正常类型的另一个版本id
可以。
我听说这与自主工作有关 。 但是我仅具有关于移动语义的基本知识,并且我不理解标准中引用的答案中的神秘语言。 有人可以用常识/外行的语言解释一下吗?
如果我把一个临时a
,获得了其内容,并返回内容作为临时被分配回a
,为什么要a
被清除或不确定的?
#include <vector>
#include <iostream>
using namespace std;
template <class T>
vector<T> id(vector<T>&& v) { return std::move(v); }
template <class T>
vector<T>&& id2(vector<T>&& v) { return std::move(v);}
int main() {
vector<int> a;
a.resize(3,1);
a = id(std::move(a));
cout << a.size() << endl; //output: 3
a.resize(3,1);
a = id2(std::move(a));
cout << a.size() << endl; //output: 0
}
谢谢,
-更新-
如果我正在阅读上述重复帖子 ,则下面引用的第二个示例是关于将r-ref传递到函数外部的局部变量,无论这是r-ref还是l-ref,无论如何都是错误的。 我认为这与我的示例不太相同。 如果在我的示例中使用左引用而不是r-ref,它会起作用。 我在这方面缺少什么吗?
std::vector<int>&& return_vector(void)
{
std::vector<int> tmp {1,2,3,4,5};
return std::move(tmp);
}
std::vector<int> &&rval_ref = return_vector();
-更新2-
@pradhan。 看来问题归结为自我完成任务。 关于标准容器自移动分配的行为库选择,这让我感到困扰。 如果您以旧的方式对std::vector
进行自我分配,那就很好了,但是当您自我移动分配时,这是未定义的行为。 除非存在本质上的问题,否则让标准容器允许自移动分配和自分配一样更自然(向后兼容)?
#include <vector>
#include <iostream>
int main() {
std::vector<int>a{1,2,3};
a = a;
std::cout << a.size() << std::endl; //output: 3
a = std::move(a);
std::cout << a.size() << std::endl; //output: 0
}
您的函数id2
不执行任何操作,代码等效于
a = std::move(a);
您所链接的Howard Hinnant的回答解释说,这本身是不允许的。 用外行的话来说:该标准不需要支持自动移动分配。 因此,不需要移动分配运算符的实现来执行自赋值的测试,并且结果为未定义行为。
如果您使a=std::move(a)
合法,那么它什么也不会做。 问题在于,这需要进行检查,这对于非自我移动分配情况是多余的,因此对所有这些分配都进行了悲观评估。
您违反了rvalue引用不是alias的约定(这是调用库函数的要求)。 问题中提到的霍华德·辛南特(Howard Hinnant)的答案包含标准文字和自动执行的应用程序。 这是实际的结果:
将移动分配实现为:
T& T::operator=(T&& other)
{
clear();
swap(*this, other);
return *this;
}
或更安全的异常变体:
T& T::operator=(T&& other)
{
swap(*this, other);
other.clear();
return *this;
}
只要遵守别名惯例,这也是安全的。
很明显,如果您使用别名,为什么这两种实现方式都会产生一个空对象。
顺便说一句, id2
返回一个右值引用没有什么问题。 问题在于a = id2(a);
它使用右值引用为同一表达式中的另一个对象引用加上别名。
您问题的链接和Hinnant的答案都处理了标准对标准库的实现提出的要求。 a=std::move(a)
本质上没有错。 如果a
是类类型T
,则a=std::move(a)
取决于T
的实现。 该标准允许(标准)库实现在给定右值引用参数时做出唯一的引用假设。 当a
具有T=vector<U>
, a=std::move(a)
违反唯一参考假设。 由于您违反了图书馆合同,因此产生了UB。 但是,您可以拥有自己的类,该类的move构造函数实现具有artst a=std::move(a)
的完美定义的行为。 该标准通常没有提及自移动分配。 它仅指定标准库实现者需要支持什么,以及如果他们愿意的话,他们可以选择不选择什么。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.