Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/141.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 右值成员真的也是右值吗?_C++_Visual C++_C++11 - Fatal编程技术网

C++ 右值成员真的也是右值吗?

C++ 右值成员真的也是右值吗?,c++,visual-c++,c++11,C++,Visual C++,C++11,右值的成员也是右值-这很有道理。这要么是VC++特有的bug,要么是我对右值理解的bug 以这个玩具代码为例: #include <vector> #include <iostream> using namespace std; struct MyTypeInner { MyTypeInner() {}; ~MyTypeInner() { cout << "mt2 dtor" &

右值的成员也是右值-这很有道理。这要么是VC++特有的bug,要么是我对右值理解的bug

以这个玩具代码为例:

#include <vector>
#include <iostream>
using namespace std;

struct MyTypeInner
{
    MyTypeInner()   {};
    ~MyTypeInner()                     { cout << "mt2 dtor" << endl; }
    MyTypeInner(const MyTypeInner& other)  { cout << "mt2 copy ctor" << endl; }
    MyTypeInner(MyTypeInner&& other)       { cout << "mt2 move ctor" << endl; }
    const MyTypeInner& operator = (const MyTypeInner& other)
    {
        cout << "mt2 copy =" << endl;       return *this;
    }
    const MyTypeInner& operator = (MyTypeInner&& other)
    {
        cout << "mt2 move =" << endl;       return *this;
    }
};

struct MyTypeOuter
{
    MyTypeInner mt2;

    MyTypeOuter()   {};
    ~MyTypeOuter()                     { cout << "mt1 dtor" << endl; }
    MyTypeOuter(const MyTypeOuter& other)  { cout << "mt1 copy ctor" << endl;  mt2 = other.mt2; }
    MyTypeOuter(MyTypeOuter&& other)       { cout << "mt1 move ctor" << endl;  mt2 = other.mt2; }
    const MyTypeOuter& operator = (const MyTypeOuter& other)    
    {
        cout << "mt1 copy =" << endl;       mt2 = other.mt2;   return *this;
    }
    const MyTypeOuter& operator = (MyTypeOuter&& other)
    {
        cout << "mt1 move =" << endl;   mt2 = other.mt2;    return *this;
    }
};

MyTypeOuter func()   {  MyTypeOuter mt; return mt; }

int _tmain()
{
    MyTypeOuter mt = func();
    return 0;
}
#包括
#包括
使用名称空间std;
结构MyTypeInner
{
MyTypeInner(){};

~MyTypeInner(){cout这里的问题不是
rvalue
的成员是否是
rvalue
的成员,因为您在赋值运算符中处理左值

在此移动赋值运算符中

const MyTypeOuter& operator = (MyTypeOuter&& other)
{
    cout << "mt1 move =" << endl;
    mt2 = other.mt2;
    return *this;
}

请参阅。

此处的问题不在于
rvalue
的成员是否为
rvalue
,因为您在赋值运算符中处理左值

在此移动赋值运算符中

const MyTypeOuter& operator = (MyTypeOuter&& other)
{
    cout << "mt1 move =" << endl;
    mt2 = other.mt2;
    return *this;
}

请参阅。

此处的问题不在于
rvalue
的成员是否为
rvalue
,因为您在赋值运算符中处理左值

在此移动赋值运算符中

const MyTypeOuter& operator = (MyTypeOuter&& other)
{
    cout << "mt1 move =" << endl;
    mt2 = other.mt2;
    return *this;
}

请参阅。

此处的问题不在于
rvalue
的成员是否为
rvalue
,因为您在赋值运算符中处理左值

在此移动赋值运算符中

const MyTypeOuter& operator = (MyTypeOuter&& other)
{
    cout << "mt1 move =" << endl;
    mt2 = other.mt2;
    return *this;
}



请参阅。

您是否对其进行了全面优化编译?否。通过优化,RVO将起作用,整个移动语义逻辑将变得非常简单。您仍然必须
std::move(other)
在构造函数中,如果要执行类似
MyTypeInner mt=func()的操作,编译器将只将成员视为右值而不移动.mt2;
那么,右值成员以何种方式单独使用右值呢?我希望这个定义在这里得到准确的体现。在语句mt2=other.mt2中,如果rhs确实是右值,那么应该调用一个移动赋值。@OfekShilon
other
在该表达式中是一个左值,除非您移动它,请参见问题。您是否编译了这个函数使用完全优化?否。使用优化RVO,整个移动语义逻辑是mincemeat。您仍然必须在构造函数中使用
std::move(other)
,如果要执行类似
MyTypeInner mt=func()的操作,编译器只会将成员视为不移动的右值.mt2;
那么,右值成员以何种方式单独使用右值呢?我希望这个定义在这里得到准确的体现。在语句mt2=other.mt2中,如果rhs确实是右值,那么应该调用一个移动赋值。@OfekShilon
other
在该表达式中是一个左值,除非您移动它,请参见问题。您是否编译了这个函数使用完全优化?否。使用优化RVO,整个移动语义逻辑是mincemeat。您仍然必须在构造函数中使用
std::move(other)
,如果要执行类似
MyTypeInner mt=func()的操作,编译器只会将成员视为不移动的右值.mt2;
那么,右值成员以何种方式单独使用右值呢?我希望这个定义在这里得到准确的体现。在语句mt2=other.mt2中,如果rhs确实是右值,那么应该调用一个移动赋值。@OfekShilon
other
在该表达式中是一个左值,除非您移动它,请参见问题。您是否编译了这个函数使用完全优化?否。使用优化RVO,整个移动语义逻辑是mincemeat。您仍然必须在构造函数中使用
std::move(other)
,如果要执行类似
MyTypeInner mt=func()的操作,编译器只会将成员视为不移动的右值.mt2;
那么,右值成员以何种方式单独使用右值呢?我希望这个定义在这里得到准确的体现。在语句mt2=other.mt2中,如果rhs确实是右值,则应该调用移动赋值。@OfekShilon
other
在该表达式中是左值,除非您移动它,请参见问题。我认为OP是什么获取was
std::move(other.mt2)
而不是
std::move(other.mt2);
,两者都会导致调用move构造函数,但前者显示右值的成员本身是右值(顺便说一句,左值的流行定义并不总是成立的,因为
mt2
有一个名称,但在第一种情况下它不是左值).我现在明白了,非常感谢。这似乎仍然是一个奇怪的语言设计选择-它现在迫使我为代码中的每种类型添加专门的移动构造函数/赋值,而不是免费享受具有移动语义的库类型的好处。但没关系(我肯定去那里会在1000个我无法想象的地方为我们添加字节)@user657267我无法解释这个问题。特别是,我没有看到提及
std::move(其他).mt2
@Ofekshil大多数时候,编译器生成的特殊函数做的事情是正确的,因此您没有那么多工作要做。您需要知道关于何时获得自由移动复制运算符和移动赋值运算符的规则(或者,更现实地说,知道在哪里查找它们)我认为OP试图得到的是
std::move(other.mt2)
而不是
std::move(other.mt2);
,两者都导致调用move构造函数,但前者显示了右值的成员本身是右值(顺便说一句,左值的流行定义并不总是成立的,因为
mt2
有一个名称,但在第一种情况下它不是左值).我现在明白了,非常感谢。这似乎仍然是一个奇怪的语言设计选择-它现在迫使我为代码中的每种类型添加专门的移动构造函数/赋值,而不是免费享受具有移动语义的库类型的好处。但没关系(我肯定去那里会在1000个我无法想象的地方为我们添加字节)@user657267我无法解释这个问题。特别是,我没有看到任何关于
std::move(other).mt2
@OfekShilon大多数时候,编译器