返回值复制问题(改善调试时间) - 这里有什么解决方案?

Chr*_* A. 2 c++ copy-constructor visual-studio-debugging return-value-optimization

我最近遇到的最有趣的C++问题如下:

我们确定(通过分析)我们的算法在MS Visual Studio 2005中的调试模式中花费了大量时间,具有以下类型的函数:

MyClass f(void)
{
      MyClass retval;
      // some computation to populate retval

      return retval;
}
Run Code Online (Sandbox Code Playgroud)

正如你们大多数人可能知道的那样,这里的返回调用一个拷贝构造函数来传递一个副本,retval然后传递析构函数retval.(注意:原因释放模式非常快,因为返回值优化.但是,我们希望在调试时关闭它,以便我们可以介入并很好地查看调试器IDE中的内容.)

所以,我们的一个人提出了一个很酷的(如果有点缺陷)解决方案,这就是创建转换运算符:

MyClass::MyClass(MyClass *t)
{
      // construct "*this" by transferring the contents of *t to *this   
      // the code goes something like this
      this->m_dataPtr = t->m_dataPtr;  

      // then clear the pointer in *t so that its destruction still works
      // but becomes 'trivial'
      t->m_dataPtr = 0;
}
Run Code Online (Sandbox Code Playgroud)

并将上述功能更改为:

MyClass f(void)
{
      MyClass retval;
      // some computation to populate retval

      // note the ampersand here which calls the conversion operator just defined
      return &retval;      
}
Run Code Online (Sandbox Code Playgroud)

现在,在你畏缩之前(我正在写这篇文章),让我解释一下这个理由.我们的想法是创建一个转换运算符,它基本上将"内容传输"转换为新构造的变量.节省的原因是因为我们不再进行深层复制,而只是通过指针传输内存.代码从10分钟的调试时间到30秒的调试时间,您可以想象,这对生产力有巨大的积极影响.当然,返回值优化在发布模式下做得更好,但代价是无法介入并观察我们的变量.

当然,大多数人会说"但这是滥用转换操作符,你不应该做这种事情",我完全同意.这是一个为什么你不应该这样做的例子(这实际上发生了:)

  void BigFunction(void)
  {
        MyClass *SomeInstance = new MyClass;

        // populate SomeInstance somehow

        g(SomeInstance);

        // some code that uses SomeInstance later
        ...
  }
Run Code Online (Sandbox Code Playgroud)

其中g定义为:

  void g(MyClass &m)
  {
      // irrelevant what happens here.
  }
Run Code Online (Sandbox Code Playgroud)

现在这是偶然发生的,即,g()当预期引用时,调用的人不应该传入指针.但是,没有编译器警告(当然).编译器确切知道如何转换,它就是这样做的.问题是对g()will 的调用(因为我们MyClass *在它预期时已经传递了它MyClass &)调用了转换运算符,这很糟糕,因为它将内部指针设置SomeInstance为0,并且SomeInstance对于之后发生的代码无效打电话给g()....随后进行了耗时的调试.

所以,我的问题是,我们如何在调试模式下获得这种加速(具有直接调试时间的好处),干净的代码无法打开使这些其他可怕错误滑过裂缝的可能性?

我也将在这个上加油,并且一旦它符合条件,就会在这个上提供我的第一笔赏金.(50分)

Pup*_*ppy 5

您需要使用称为"交换优化"的东西.

MyClass f(void)
{
      MyClass retval;
      // some computation to populate retval

      return retval;
}
int main() {
    MyClass ret;
    f().swap(ret);
}
Run Code Online (Sandbox Code Playgroud)

这将防止复制在所有模式下保持代码清洁.

你也可以尝试相同的技巧auto_ptr,但这不仅仅是一点点.