在通用参考上前进与前进
move vs forward on universal references
我正在通过对通用引用应用 std::move
和 std::forward
来尝试一个程序。直到今天,我都认为两者是相同的,但在这个程序(下面给出)中,输出让我感到惊讶。
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class X
{
string take="";
public:
template<class T>
void pass1 (T &&str) // str is a universal reference as it can bind to anything, both rvalue and lvalue references
{
take=move(str);
}
template<class T>
void pass2 (T &&str)
{
take=forward<T>(str);
}
void show()
{
cout<<"take = "<<take<<"\n";
}
}obj;
int main()
{
cout<<"using move on universal reference:-\n";
string str="he is there";
cout<<"str = "<<str<<'\n';
obj.pass1(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
cout<<"using forward on universal reference:-\n";
str="he was there";
cout<<"str = "<<str<<'\n';
obj.pass2(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
return 0;
}
输出:
using move on universal reference:-
str = he is there
take = he is there
str is empty
using forward on universal reference:-
str = he was there
take = he was there
str isnt empty
*/
我的问题是:
- 为什么输出不同?
move
和 forward
的工作方式不一样吗?它们的工作方式有何不同(在上述代码的上下文中)?
当然,它们是不同的。如果它们相同,则您只需要一个。
move
从提供的右值或左值构造右值。 forward
破译所提供参数的实际类型。
T &&
已重命名为转发引用。
在您的第一个示例中,您显式调用了 std::move
,因此 str
成为一个 r 值引用,并且它的内容从 main 移动到 X
中的成员。
在第二个例子中你使用 std::forward
。当 T
是右值引用时在 T
上调用 std::forward
会将右值引用转发给 operator=
并且 operator=(std::String&&)
将被调用。如果 T
是左值,则传递左值引用。因为我们有一个左值,所以 operator=(const std::string&)
将被调用,我们复制 str
而不是从它移动。
了解两件事:
1)'move'不保证能动
2) 'forward' 不转发代码。
move 是无条件运算符
forward 是一个条件运算符。
困惑??
通用引用意味着它们可以绑定任何东西,包括右值和左值。 move
& forward
不要字面上移动任何东西而是执行转换,即它们将参数转换为 rvalue
。不同之处在于 move
无条件地转换而 forward
将有条件地转换:只有当它的参数用右值初始化时它才会转换为右值。所以 move
总是投射而 forward
有时投射。
因此,上述情况下的 forward
不会清空字符串,因为 lvalue (ie str)
已传递,因此它转发 str
作为左值。
我正在通过对通用引用应用 std::move
和 std::forward
来尝试一个程序。直到今天,我都认为两者是相同的,但在这个程序(下面给出)中,输出让我感到惊讶。
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class X
{
string take="";
public:
template<class T>
void pass1 (T &&str) // str is a universal reference as it can bind to anything, both rvalue and lvalue references
{
take=move(str);
}
template<class T>
void pass2 (T &&str)
{
take=forward<T>(str);
}
void show()
{
cout<<"take = "<<take<<"\n";
}
}obj;
int main()
{
cout<<"using move on universal reference:-\n";
string str="he is there";
cout<<"str = "<<str<<'\n';
obj.pass1(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
cout<<"using forward on universal reference:-\n";
str="he was there";
cout<<"str = "<<str<<'\n';
obj.pass2(str);
obj.show();
if (str.empty())
cout<<"str is empty\n\n";
else
cout<<"str isnt empty\n\n";
return 0;
}
输出:
using move on universal reference:-
str = he is there
take = he is there
str is empty
using forward on universal reference:-
str = he was there
take = he was there
str isnt empty
*/
我的问题是:
- 为什么输出不同?
move
和forward
的工作方式不一样吗?它们的工作方式有何不同(在上述代码的上下文中)?
当然,它们是不同的。如果它们相同,则您只需要一个。
move
从提供的右值或左值构造右值。 forward
破译所提供参数的实际类型。
T &&
已重命名为转发引用。
在您的第一个示例中,您显式调用了 std::move
,因此 str
成为一个 r 值引用,并且它的内容从 main 移动到 X
中的成员。
在第二个例子中你使用 std::forward
。当 T
是右值引用时在 T
上调用 std::forward
会将右值引用转发给 operator=
并且 operator=(std::String&&)
将被调用。如果 T
是左值,则传递左值引用。因为我们有一个左值,所以 operator=(const std::string&)
将被调用,我们复制 str
而不是从它移动。
了解两件事:
1)'move'不保证能动
2) 'forward' 不转发代码。
move 是无条件运算符
forward 是一个条件运算符。
困惑??
通用引用意味着它们可以绑定任何东西,包括右值和左值。 move
& forward
不要字面上移动任何东西而是执行转换,即它们将参数转换为 rvalue
。不同之处在于 move
无条件地转换而 forward
将有条件地转换:只有当它的参数用右值初始化时它才会转换为右值。所以 move
总是投射而 forward
有时投射。
因此,上述情况下的 forward
不会清空字符串,因为 lvalue (ie str)
已传递,因此它转发 str
作为左值。