【问题标题】:Does move semantics of C++11 overperfom copy-on-write idiom?移动 C++11 的语义是否优于写时复制习语?
【发布时间】:2012-01-15 14:38:39
【问题描述】:

我可能在这里感到困惑,但我确实理解的是:

  • COW 将返回一个“假”副本,直到其中一个调用者想要进行一些修改。
  • Move Semantic 在所有情况下都会返回“假”副本。

所以如果我的目的是拥有一个只需要读取而不需要更新的对象,我应该只等待我的 C++ 编译器中的移动语义支持?

我说的对吗?

【问题讨论】:

    标签: c++ c++11 idioms


    【解决方案1】:

    移动语义不会返回“假”副本。相反,在复制操作中,它授予复制者删除原始副本的权限。

    一个激励性的例子可能是有启发性的:

    std::vector<int> bigData;
    
    // fill bigData
    
    std::vector<std::vector<int> > listOfData;
    
    listOfData.push_back(std::move(bigData));
    // after this point, the contents of bigData are unspecified (however accessing it is _not_ undefined behavior)
    

    如果没有移动语义,您需要复制bigData 以将其插入listOfData,或者手动将swap() 旋转到listOfData 中的新空向量中。但是使用移动语义,std::vector 的右值引用构造函数(又名移动构造函数)在复制新数据时由push_back 调用,有权丢弃bigData 的旧内容 - 因此,它是允许的例如,窃取bigData 的内部指针并将bigData 重置为空向量。

    移动语义通常比 COW 语义更快,因为它们不需要维护对共享只读数据的引用计数。然而,它们受到更多限制 - 您无法使用移动语义为您的数据创建多个引用计数别名,您可以轻松方便地在容器之间打乱数据。

    另请注意,最新版本的 GCC 和 Microsoft Visual C++ 都支持右值引用和移动语义(GCC 与 --std=c++0x),因此没有理由不立即开始使用它们。

    【讨论】:

    • 定义垃圾:未知但有效状态。
    • “bigData 的内容是未指定的(但是访问它是 not 未定义的行为)” - 所以结果是由被复制的类型在其移动构造函数中定义的?如果没有定义移动构造函数,std::move 会退回到复制构造函数吗?或者也许在std::swap
    • @KarlKnechtel:std::move 不会移动任何东西。它所做的只是将其转换为T&amp;&amp; r 值引用,这可以触发调用移动构造函数(或移动赋值运算符)。实际执行移动的是移动构造函数。将创建默认移动构造函数,就像默认复制构造函数一样。默认的移动构造函数会自行移动每个元素。对于基本类型,默认移动只是一个副本。对于用户定义的类型,它是对移动构造函数的调用。
    【解决方案2】:

    copy-on-write 和 move 构造函数是不同的东西。

    让我们谈谈 COW 实现很普遍的字符串。假设您有支持 COW 和移动语义的字符串实现。然后考虑这段代码:

    cow::string foo() { return string("foo"); } // move CTOR is in effect here.
    
    cow::string a = foo(); // move ctor in effect
    cow::string b = a; // copy ctor in effect
    

    ab 这里将共享相同的分配字符序列。在这里

    std::string foo() { return string("foo"); } // move CTOR is in effect here.
    
    std::string a = foo(); // move ctor in effect
    std::string b = a; // copy ctor in effect
    

    ab 将分配并保存两个不同的字符序列,使内存消耗加倍。

    【讨论】:

    • 我的理解是,字符串的 COW 实现虽然很明显,但实际上并不普遍,因为人们发现它们会破坏多线程环境中的性能。
    • Karl,您对“它们会破坏多线程环境中的性能”这句话有任何实际的证明吗?如今,这些处理器等听起来像是一个城市神话。是的,InterlockedIncrement 和朋友确实会产生一些开销,但另外的堆分配也需要多线程环境中的一些同步原语。目前尚不清楚什么更糟。无论如何,这取决于具体情况。
    • 我用“我的理解是这样的”和“[其他] 人发现的”这样的短语来表达陈述是有充分理由的。 ;)
    • 我们在 COW、动态内存分配和锁方面的经验很糟糕。 COW 字符串在多线程环境中并不总是很好
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-02
    • 2012-07-05
    • 1970-01-01
    • 2013-09-04
    • 2014-08-16
    • 2012-08-20
    相关资源
    最近更新 更多