科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件Visual C++ 2005中的命名返回值优化

Visual C++ 2005中的命名返回值优化

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

描述了Visual C++编译器在不同情况下,是怎样消除多余的复制构造函数和析构函数的。

作者:谢启东编译 来源:天极开发 2007年11月16日

关键字:

  • 评论
  • 分享微博
  • 分享邮件
优化的局限性

  在某些情况下,NRVO优化不会起作用,以下是存在优化局限性的一些示例程序。

  Sample3.cpp:含有例外的代码

  在例外(Exception)情况中,隐藏参数必须在它被替换的临时范围内析构。

//RVO类定义在sample1.cpp中

#include <stdio.h>

RVO MyMethod (int i)
{
 RVO rvo;
 rvo.mem_var = i;
 throw "I am throwing an exception!";
 return (rvo);
}

int main()
{
 RVO rvo;
 try
 {
  rvo=MyMethod(5);
 }
 catch (char* str)
 {
  printf ("I caught the exception\n");
 }
}

  不带NRVO编译(cl /Od /EHsc sample3.cpp),输出如下:

I am in constructor
I am in constructor
I am in destructor
I caught the exception
I am in destructor

  如果注释掉“throw”语句,输出将会如下如示:

I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor

  现在,如果注释掉“throw”语句,并且用NRVO编译,程序输出如下:

I am in constructor
I am in constructor
I am in destructor
I am in destructor

  这就是说,不管打开或关闭NRVO选项,sample3.cpp的程序行为都一样。

  Sample4.cpp:不同的命名对象

  想要充分利用优化,所有的返回路径必须都返回相同的命名对象,请看如下示例代码:

#include <stdio.h>

class RVO
{
 public:
  RVO(){printf("I am in constructor\n");}
  RVO (const RVO& c_RVO) {printf ("I am in copy constructor\n");}
 int mem_var;
};

RVO MyMethod (int i)
{
 RVO rvo;
 rvo.mem_var = i;
 if (rvo.mem_var == 10)
  return (RVO());
 return (rvo);
}

int main()
{
 RVO rvo;
 rvo=MyMethod(5);
}

  优化打开时(cl /O2 sample4.cpp)的输出,与没有进行任何优化时(cl /Od sample.cpp)的输出是一样的。因为不是所有的返回路径都返回同一命名对象,所以NRVO此时不起任何作用。

I am in constructor
I am in constructor
I am in copy constructor

  如果把上述代码的所有返回路径都改为返回rvo(如下例Sample4_modified.cpp),此时优化就会消除多余的复制构造函数。

  经过修改的Sample4_Modified.cpp,以利用NRVO。

#include <stdio.h>

class RVO
{
 public:
  RVO(){printf("I am in constructor\n");}
  RVO (const RVO& c_RVO) {printf ("I am in copy constructor\n");}
 int mem_var;
};

RVO MyMethod (int i)
{
 RVO rvo;
 if (i==10)
  return (rvo);
 rvo.mem_var = i;
 return (rvo);
}

int main()
{
 RVO rvo;
 rvo=MyMethod(5);
}

  此时(cl /O2 Sample4_Modified.cpp)的输出:

I am in constructor
I am in constructor

  Sample5.cpp:EH限制

  以下的Sample5与Sample4基本一致,除了增加了RVO类的析构函数,并具有多重返回路径,且引入的析构函数在函数中创建了一个EH状态。由于编译器跟踪的复杂性,此类对象通常需要被析构,但它阻止了返回值优化,这也是Visual C++ 2005在将来需要改进的地方。

//RVO类定义在sample1.cpp中

#include <stdio.h>
RVO MyMethod (int i)
{
 RVO rvo;
 if (i==10)
  return (rvo);
 rvo.mem_var = i;
 return (rvo);
}

int main()
{
 RVO rvo;
 rvo=MyMethod(5);
}

  不论打开或关闭优化,Sample5.cpp都会产生相同的结果。

I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor

  要想打开NRVO优化,必须消除多重返回点,可以像如下所示修改MyMethod:

RVO MyMethod (int i)
{
 RVO rvo;
 if (i!=10)
  rvo.mem_var = i;
 return(rvo);
}

  Sample6.cpp:内联汇编限制

  当命名返回对象被内联汇编语句所引用时,编译器不会进行NRVO优化,请看下例代码:

#include <stdio.h>
// RVO类定义在sample1.cpp中

RVO MyMethod (int i)
{
 RVO rvo;
 __asm {
  mov eax,rvo //可以注释掉此行
  mov rvo,eax //可以注释掉此行
 }
 return (rvo);
}

int main()
{
 RVO rvo;
 rvo=MyMethod(5);
}

  即使打开优化选项(cl /O2 sample6.cpp)来编译sample6.cpp,NRVO也不会起作用。这是因为内联汇编语句中引用了返回对象,因此,打开或关闭优化选项,输出都会像如下所示:

I am in constructor
I am in constructor
I am in copy constructor
I am in destructor
I am in destructor
I am in destructor

  从以上输出,可清楚地看到,复制构造函数和析构函数并没有被消除。但如果注释掉汇编语句,优化将会消除掉这些函数调用。
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章