【问题标题】:Good example of where move semantics would be beneficial移动语义有益的好例子
【发布时间】:2013-12-13 13:48:34
【问题描述】:

编辑:我希望下面的代码变慢(并且复制过多),以便我可以使用移动语义重新编写它并比较两种方法。

我在一个类中有以下代码:

std::list<boost::shared_ptr<I> > getX(){
    std::list<boost::shared_ptr<I> > a;

    for(auto kv : b) {
        if(something){
            a.push_back(kv.second);
        }
    } 

    return a;
}

double foo(){

    std::list<boost::shared_ptr<I> > a = getX();

现在我在return a 上放了一个断点,我期待看到正在制作的列表的某种副本(std::list 复制构造函数,然后是每个I 对象复制构造函数。但是,调试器改为闯入 amdsecgs.asm:

LEAF_ENTRY __security_check_cookie, _TEXT

cmp rcx, __security_cookie      ; check cookie value in frame
jne ReportFailure               ; if ne, cookie check failure
rol rcx, 16                     ; make sure high word is zero
test cx, -1
jne RestoreRcx
db 0f3h                         ; (encode REP for REP RET)
ret                             ; no overrun, use REP RET to avoid AMD
                                ; branch prediction flaw after Jcc

而且我无法看到正在制作的列表的任何副本。我希望看到复制的列表,然后复制每个 i 对象。

(我问这个的原因是因为我正在尝试编写一些代码,这些代码对于使用移动语义来加速非常好)。

这段代码是否通过返回值优化进行了优化?如果是这样,我有什么办法可以修改代码以防止应用 RVO?

【问题讨论】:

  • 我的理解是,您仍在复制列表以通过复制返回它(因为原始列表是堆栈自动对象,当它超出范围时会被销毁),它只是没有被复制当它因为移动语义而被分配给 a 时。为什么你现在在堆中创建你的列表并只返回一个智能指针?这将消除所有复制。
  • @Julius 我想创建副本来展示(通过重写代码)移动语义的优势....

标签: c++ visual-c++ c++11 copy move


【解决方案1】:

一个选项可能是:

std::list<boost::shared_ptr<I> > getX(){
    using list = std::list<boost::shared_ptr<I> >;
    list empty;
    list a;

    for(auto kv : b) {
        if(something){
            a.push_back(kv.second);
        }
    } 

    return list( a.empty() ? empty : a );
}

这应该会破坏 RVO/NRVO 并强制编译器复制返回的列表。

【讨论】:

    【解决方案2】:

    如果您只想演示移动语义提供的加速,您可以使用一种情况,您实际上不必与编译器抗争以使其有用,例如在其范围内移动自动范围集合时,像这样:

    typedef vector<float> Grades;
    unordered_map<int, string> idsToNames;
    unordered_map<int, Grades> idsToGrades;
    //ids and names being used seperatly
    ...
    //it would now be more useful to merge them
    struct StudentInfo {
        string mName; Grades mGrades; 
        StudentInfo(string && name, Grades && grades):mName(name),mGrades(grades){}
    };
    
    unordered_map<int, StudentInfo> idsToStudentInfo;
    
    for(pair<int, string>& s : idsToNames)  {
        idsToStudentInfo.insert(
             make_pair(s.first, 
                 StudentInfo(std::move(s.second),std::move(idsToGrades[s.first]))
             )
        );
    }
    

    所以在这里,不是复制 Grades 向量和字符串(char 向量),而是在 mName 字符串和 mGrades 字符串的移动构造函数中交换它们,速度相当快。

    【讨论】:

      猜你喜欢
      • 2017-04-10
      • 2013-12-16
      • 1970-01-01
      • 2021-09-24
      • 1970-01-01
      • 2012-05-30
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多