2010-06-27 128 views
-1

我想了解C++的新功能,即移动构造函数和赋值X::operator=(X&&),我发现interesting example,但我唯一不甚了解,但更不同意的是移动ctor和赋值运算符中的一行(标注在下面的代码):移动构造/运营商=

MemoryBlock(MemoryBlock&& other) 
    : _data(NULL) 
    , _length(0) 
{ 
    std::cout << "In MemoryBlock(MemoryBlock&&). length = " 
      << other._length << ". Moving resource." << std::endl; 

    // Copy the data pointer and its length from the 
    // source object. 
    _data = other._data; 
    _length = other._length; 

    // Release the data pointer from the source object so that 
    // the destructor does not free the memory multiple times. 
    other._data = NULL; 
    other._length = 0;//WHY WOULD I EVEN BOTHER TO SET IT TO ZERO? IT DOESN'T MATTER IF IT'S ZERO OR ANYTHING ELSE IT IS JUST A VALUE. 
} 

所以我的问题是:我必须lenght_的值设置为零或我可以离开它不变?不会有任何内存泄漏,并且一个表达式不会有任何缺陷。

+0

也许[这个答案](http://stackoverflow.com/questions/3106110/can-someone-please-explain-move-semantics-to-me/3109981#3109981)也有帮助... – fredoverflow 2010-06-27 20:49:16

+0

几个小细节我想纠正。首先,由于此构造函数正在初始化_data和_length,然后复制到它们,它应该只用正确的值进行初始化。 我不会说'其他。data = NULL'就是'释放',它更像'unsetting',没有释放内存。 此外,你应该使用'nullptr'而不是'NULL',大致相同,但是'nullptr'是*正确的* C++。 避免使用'std :: endl'也是可取的,它会让程序在等待输出被刷新时停下来。除非你需要这个功能,否则更喜欢'“\ n”'。 – thecoshman 2013-07-02 13:50:18

回答

6

因为“移出”对象最终仍然会被破坏,所以你必须保持一致的状态。当然,具体怎么做取决于你的对象,在这种情况下,它显然意味着将数据指针置零并将长度设置为零。

+0

@Terry但是如果零或千是为什么会有所作为?它仍然是有效的int。 – 2010-06-27 17:04:48

+0

@ A-ha有效值与正确/一致的值有区别。 – 2010-06-27 17:25:23

+0

@Josh不在这种情况下AFAIC – 2010-06-27 17:49:40

0

出乎意料的是,程序员决定长度总是应该有一个正确的值。如果您没有设置它,在析构函数的代码将不再打印正确的事情:

std::cout << "In ~MemoryBlock(). length = " 
       << _length << "."; 
+0

你不明白我的问题是什么。 – 2010-06-27 17:09:23

+0

你错了。如果我指定零或不是没关系。 dtor中的值仍将被打印。 – 2010-06-27 17:51:10

+0

@A-ha:如果你没有设置other._length为0,它仍然在析构函数中输出为0。 – Bill 2010-06-27 19:36:34

0

_length_data是语义相关的项目。对于处于一致状态的对象,_length应该始终告诉您在_data指向的块中有多少内存。当_data指向100个块,_length应当是100时_data点1块,_length应该是1.如果_data不指向任何东西(NULL),然后_length应该是0。否则,如果_data是NULL和_length是100,那么你的对象处于不一致的状态。当我这样做:

for (int i = 0; i < _length; ++i) 
{ 
    // do something with _data[i], such as: 
    _data[i] = 0; 
} 

我不应该崩溃。如果您未能正确设置_length,则会崩溃。 真正的问题是,为什么你会故意将对象置于不一致的状态,导致崩溃?

+0

,但在这种情况下,您有正确的length_已在上面的行中分配。我所说的一行中所做的只是使tmp对象无效,所以我再说一遍:不,我认为length_的值无关紧要。 – 2010-06-27 18:08:45

+0

继续在无效的对象中。 – 2010-06-27 18:24:06

+0

@A-ha:'other._length'只设置在一个地方:'other._length = 0;'从逻辑上讲,你的观点是可以将对象置于不一致的状态。我不同意。 – Bill 2010-06-27 19:35:40

0

这个问题很难得到明确的答案。移动语义是新的,C++社区仍在学习如何正确使用它。

我看到的一个合理的规则是,“离开”对象必须安全地破坏并且能够被赋予新的值。将_length设置为零不必满足该规则,坦率地说,我不确定int表示无效状态的值是多少;在你的情况下可能是-1?

0

您正在移动数据的对象可能不是临时的(例如,您可能使用std :: move) - 将对象置于无效状态将会是一种糟糕的形式。

+0

如此重置它的值是可以接受的吗?有趣,有趣... – 2010-06-27 20:41:22

+1

是的,因为这是移动构造函数的用途。您将一个对象内容的所有权转移给另一个对象。 – DanDan 2010-06-27 21:10:32

0

将该值设置为零只会显示一致性。但是,答案真的取决于如何打算使用_length来销毁对象。如果不使用长度来确定是否应删除_data(当移动的对象超出范围时),那么我们可以说移动对象时忽略_length是安全的。只要确保在任何派生类型中保持一致性,并确保您忽略_length的决定已记录在案。