5

我只是c ++ 11移动操作的初学者,所以玩它。但是发现了一些我无法理解的东西。

#include <iostream>
using namespace std;

class A{
    public:
        A(){cout << "default ctor" << endl;}
        A(const string& str):_str{str}{cout << "parameter ctor" << endl;}
        A(A&& obj):_str{std::move(obj._str)}{cout << "move ctor" << endl;}
        A& operator =(A&& rhs){_str = std::move(rhs._str);cout << "move assignment operation" << endl; return *this;}
        void print(){cout << _str << endl;}
    private:
        string _str;
};

int main(){
    A a("rupesh yadav"); // parameter ctor
    A b(std::move(a));   // move ctor

    cout << "print a: ";
    a.print();           // NOT printing  --> CORRECT!!
    cout << "print b: ";
    b.print();           // printing      --> CORRECT!!

    b = std::move(a);    // i don't know may be silly but still lets do it WHY NOT!!!, could be just mistake??

    cout << "print a: "; 
    a.print();           // printing      --> WRONG!! 
    cout << "print b: "; 
    b.print();           // NOT printing  --> WRONG!!
}

我期望该b = std::move(a)操作会表现出不同的行为,因为我第二次在对象上应用移动,但它将左侧对象b复制右侧对象a,这部分我不明白。

或者我在编程中做错了什么。如果我在移动操作中做错了什么,请帮忙。

编辑:我知道这是未定义的行为。我的疑问是我是否会再做一次,那么它是从对象a复制到对象b,如果我再次做同样的事情,那么会将对象b复制到对象a吗?

因此它是从左到右和从右到左复制表格,为什么?

4

2 回答 2

6

你不能从同一个物体移动两次。

在您第一次搬入后aba一个“有效但未指定的状态”(不记得确切的术语)。然后,你又试图搬进a去!现在一切都乱套了。(我怀疑,在内部,数据指针刚刚被交换了。)b

根本不要这样做。我认为没有理由想要。

于 2016-05-09T09:56:30.587 回答
4

没有什么能阻止你从一个物体上移动两次。标准库对象在移出时必须处于“有效但未指定”状态。唯一的条件是“满足对象的不变量并且对对象的操作按照其类型的指定行为” 17.3.28。例如,移动构造函数std::string说:

basic_string(const basic_string& str);

basic_string(basic_string&& str) noexcept;

2效果:构造一个类对象,basic_string如表 [tab:strings.ctr.cpy] 中所示。在第二种形式中,str保持在具有未指定值的有效状态。

移动构造函数没有先决条件,再次从它移动不会违反它的不变量。此外,由于它在标准中明确概述,根据定义,它不是未定义的行为。但是,您可以通过省略来争辩说,违反不变量std::string是未定义的行为,但这会导致我们:

打电话operator<<std::string不允许的吗?来自的描述cppreference说:

表现为 FormattedOutputFunction。构造并检查哨兵对象后,确定输出格式填充如下:

  • 如果str.size()不小于,则按原样os.width()使用范围[str.begin(), str.end())

  • 否则,如果(os.flags() & ios_base::adjustfield) == ios_base::left,将字符的os.width()-str.size()副本 os.fill()放在字符序列之后

  • 否则,将字符的os.width()-str.size()副本os.fill()放在字符序列之前

size()begin()并且end()没有先决条件,因此代码是完全安全的。

于 2016-05-09T10:27:15.057 回答