Linux | c&cpp | Email | github | QQ群:425043908 关注本站

itarticle.cc

您现在的位置是:网站首页 -> 代码相关 文章内容

C++编译器优化:Copy Elision(省略不必要的拷贝)-itarticl.cc-IT技术类文章记录&分享

发布时间: 9年前代码相关 100人已围观返回

为避免对临时对象进行不必要的拷贝,C++编译器常使用一种名为Copy Ellision(拷贝去除)的优化技术,该技术至少包括以下两项内容:

返回值优化(RVO),即通过将返回值所占空间的分配地点从被调用端转移至调用端的手段来避免拷贝操作。

返回值优化包括具名返回值优化(NRVO)与无名返回值优化(URVO),两者的区别在于返回值是具名的局部变量还是无名的临时对象。

右值拷贝优化,当某一个类类型的临时对象被拷贝赋予同一类型的另一个对象时,通过直接利用该临时对象的方法来避免拷贝操作

这项优化只能用于右值(临时对象),不能用于左值。

如果需要测试编译器是否应用了Copy Ellision优化技术,可使用以下代码(摘自cppnext)。

#include <iostream>


struct X

{

X() : id(instances++)

{

std::cout << "X" << id << ": construct\n";

}


X(X const& rhs) : id(instances++)

{

std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";

++copies;

}


// This particular test doesn't exercise assignment, but for

// completeness:

X& operator=(X const& rhs)

{

std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n";

}


~X() { std::cout << "X" << id << ": destroy\n"; }


unsigned id;


static unsigned copies;

static unsigned instances;

};


unsigned X::copies = 0;

unsigned X::instances = 0;


#define CHECK_COPIES( stmt, min, max, comment ) \

{ \

unsigned const old_copies = X::copies; \

\

std::cout << "\n" comment "\n" #stmt "\n===========\n"; \

{ \

stmt; \

} \

unsigned const n = X::copies - old_copies; \

if (n > max) \

std::cout << "*** max is too low or compiler is buggy ***\n"; \

if (n < min) \

std::cout << "*** min is too high or compiler is buggy ***\n"; \

\

std::cout << "-----------\n" \

<< n << "/" << max \

<< " possible copies made\n" \

<< max - n << "/" << max - min \

<< " possible elisions performed\n\n"; \

\

if (n > min) \

std::cout << "*** " << n - min \

<< " possible elisions missed! ***\n"; \

}


struct trace

{

trace(char const* name)

: name(name)

{

std::cout << "->: " << name << "\n";

}


~trace()

{

std::cout << "<-: " << name << "\n";

}


char const* name;

};


void sink(X a)

{

trace t("sink");

}


X nrvo_source()

{

trace t("nrvo_source");

X a;

return a;

}


X urvo_source()

{

trace t("urvo_source");

return X();

}


X identity(X a)

{

trace t("identity");

return a;

}


X lvalue_;

X& lvalue()

{

return lvalue_;

}

typedef X rvalue;


int main()

{

// Double parens prevent "most vexing parse"

CHECK_COPIES( X a(( lvalue() )), 1, 1, "Direct initialization from lvalue");

CHECK_COPIES( X a(( rvalue() )), 0, 1, "Direct initialization from rvalue");


CHECK_COPIES( X a = lvalue(), 1, 1, "Copy initialization from lvalue" );

CHECK_COPIES( X a = rvalue(), 0, 1, "Copy initialization from rvalue" );


CHECK_COPIES( sink( lvalue() ), 1, 1, "Pass lvalue by value" );

CHECK_COPIES( sink( rvalue() ), 0, 1, "Pass rvalue by value" );


CHECK_COPIES( nrvo_source(), 0, 1, "Named return value optimization (NRVO)" );

CHECK_COPIES( urvo_source(), 0, 1, "Unnamed return value optimization (URVO)" );


// Just to prove these things compose properly

CHECK_COPIES( X a(urvo_source()), 0, 2, "Return value used as ctor arg" );


// Expect to miss one possible elision here

CHECK_COPIES( identity( rvalue() ), 0, 2, "Return rvalue passed by value" );

}

代码说明

lvalue()函数返回struct X类型的全局变量lvalue_的引用,故lvalue()函数返回左值,可用于测试右值拷贝优化。

rvalue()函数返回struct X类型的构造器所构建的临时对象,故rvalue()函数返回右值,可用于测试右值拷贝优化。

nrvo_source()函数返回struct X类型的局部变量a,故nrvo_source()函数可用于测试具名返回值优化。

urvo_source()函数返回struct X类型的构造器所构建的临时对象,故urvo_source()函数可用于测试无名返回值优化。

第109,110行分别用左右值来测试类对象直接初始化中的右值拷贝优化。

第112,113行分别用左右值来测试类对象拷贝初始化中的右值拷贝优化。

第115,116行分别用左右值来测试普通函数实参中的右值拷贝优化。

第118,119行分别用于测试具名返回值优化与无名返回值优化。

Windows平台下使用gcc4.6.1编译运行结果如下

X0: construct


Direct initialization from lvalue

X a(( lvalue() ))

===========

X1: <- X0: **copy**

X1: destroy

-----------

1/1 possible copies made

0/0 possible elisions performed



Direct initialization from rvalue

X a(( rvalue() ))

===========

X2: construct

X2: destroy

-----------

0/1 possible copies made

1/1 possible elisions performed



Copy initialization from lvalue

X a = lvalue()

===========

X3: <- X0: **copy**

X3: destroy

-----------

1/1 possible copies made

0/0 possible elisions performed



Copy initialization from rvalue

X a = rvalue()

===========

X4: construct

X4: destroy

-----------

0/1 possible copies made

1/1 possible elisions performed



Pass lvalue by value

sink( lvalue() )

===========

X5: <- X0: **copy**

->: sink

<-: sink

X5: destroy

-----------

1/1 possible copies made

0/0 possible elisions performed



Pass rvalue by value

sink( rvalue() )

===========

X6: construct

->: sink

<-: sink

X6: destroy

-----------

0/1 possible copies made

1/1 possible elisions performed



Named return value optimization (NRVO)

nrvo_source()

===========

->: nrvo_source

X7: construct

<-: nrvo_source

X7: destroy

-----------

0/1 possible copies made

1/1 possible elisions performed



Unnamed return value optimization (URVO)

urvo_source()

===========

->: urvo_source

X8: construct

<-: urvo_source

X8: destroy

-----------

0/1 possible copies made

1/1 possible elisions performed



Return value used as ctor arg

X a(urvo_source())

===========

->: urvo_source

X9: construct

<-: urvo_source

X9: destroy

-----------

0/2 possible copies made

2/2 possible elisions performed



Return rvalue passed by value

identity( rvalue() )

===========

X10: construct

->: identity

X11: <- X10: **copy**

<-: identity

X11: destroy

X10: destroy

-----------

1/2 possible copies made

1/2 possible elisions performed


*** 1 possible elisions missed! ***

X0: destroy

发布时间: 9年前代码相关100人已围观返回回到顶端

很赞哦! (1)

文章评论

  • 请先说点什么
    热门评论
    99人参与,0条评论

站点信息

  • 建站时间:2016-04-01
  • 文章统计:728条
  • 文章评论:82条
  • QQ群二维码:扫描二维码,互相交流