科技行者

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

知识库

知识库 安全导航

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

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

  • 扫一扫
    分享文章到微信

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

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

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

关键字: Visual C++ 2005 命名返回值 优化

  • 评论
  • 分享微博
  • 分享邮件
多年来,Microsoft Visual C++编译器一直在努力寻求更新的技术与优化方式,以求最大可能地提高程序的性能。此文描述了Visual C++编译器在不同情况下,是怎样消除多余的复制构造函数和析构函数的。

   通常来说,当方法返回对象的一个实例时,会创建一个临时对象,并通过复制构造函数复制到目标对象中。在C++标准中,允许省略复制构造函数(哪怕会导致不同的程序行为),但这有一个副作用,就是编译器可能会把两个对象当成一个。Visual C++ 8.0(Visual C++ 2005)充分利用了C++标准的可伸缩性,加入了一些新的特性——命名返回值优化(NRVO)。NRVO消除了基于堆栈返回值的复制构造函数和析构函数,并去除了对多余复制构造函数和析构函数的调用,从而全面地提高了程序的性能。但要注意到,优化和未优化的代码,可能会有不同的程序行为表现。

  而在某些情况下,NRVO不会进行优化(参见优化的局限性一节),以下是一些常见的情况:

  ·不同的路径返回不同的命名对象

  ·引入EH状态的多重返回路径(甚至所有的路径中返回相同的命名对象)

  ·由内联汇编语句引用的命名返回对象

  NRVO优化概述

  以下是一个简单的示例,演示了优化是怎样被实现的:

A MyMethod (B &var)
{
 A retVal;
 retVal.member = var.value + bar(var);
 return retVal;
}

  使用上述函数的程序可能会有一个像如下所示的构造函数:

valA = MyMethod(valB);

  由MyMethod返回的值会创建在内存空间中,并通过隐藏的参数指向ValA。以下是函数中带有隐藏参数,并清晰地写明构造和析构函数时样子:

A MyMethod (A &_hiddenArg, B &var)
{
 A retVal;
 retVal.A::A(); // retVal的构造函数
 retVal.member = var.value + bar(var);
 _hiddenArg.A::A(retVal); // A的复制构造函数
 return;
 retVal.A::~A(); // retVal的析构函数
}

  从以上代码中,很明显可看出有一些可以优化的地方。最基本的想法是消除基于堆栈的临时值(retVal),并使用隐藏参数,从而消除那些基于堆栈值的复制构造函数和析构函数。以下是NRVO优化过的代码:

A MyMethod(A &_hiddenArg, B &var)
{
 _hiddenArg.A::A();
 _hiddenArg.member = var.value + bar(var);
 Return
}

  示例代码

  Sample1.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");}
  ~RVO(){printf ("I am in destructor\n");}
 int mem_var;
};

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

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

  打开或关闭NRVO编译sample1.cpp,将会产生不同的程序行为。

  不带NRVO编译(cl /Od sample1.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选项编译(cl /O2 sample1.cpp),以下是输出内容:

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

  Sample2.cpp:较复杂一点的代码

#include <stdio.h>
class A {
 public:
  A() {printf ("A: I am in constructor\n");i = 1;}
  ~A() { printf ("A: I am in destructor\n"); i = 0;}
  A(const A& a) {printf ("A: I am in copy constructor\n"); i = a.i;}
  int i, x, w;
};

class B {
 public:
  A a;
  B() { printf ("B: I am in constructor\n");}
  ~B() { printf ("B: I am in destructor\n");}
  B(const B& b) { printf ("B: I am in copy constructor\n");}
};

A MyMethod()
{
 B* b = new B();
 A a = b->a;
 delete b;
 return (a);
}

int main()
{
 A a;
 a = MyMethod();
}

  不带NRVO(cl /Od sample2.cpp)的输出如下:

A: I am in constructor
A: I am in constructor
B: I am in constructor
A: I am in copy constructor
B: I am in destructor
A: I am in destructor
A: I am in copy constructor
A: I am in destructor
A: I am in destructor
A: I am in destructor

  当打开NRVO优化时,输出如下:

A: I am in constructor
A: I am in constructor
B: I am in constructor
A: I am in copy constructor
B: I am in destructor
A: I am in destructor
A: I am in destructor
A: I am in destructor
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

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

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