c++的复制省略(copy elision)

学习 A simple C++11 Thread Pool 时,发现函数返回了std::future,而std::future的拷贝构造和拷贝赋值都是delete的,感觉有点怪,查了一下,看到 编译器优化之Copy elision、URVO、NRVO 后恍然大悟。这里做一下总结整理。

复制省略或者译作省略不必要的复制(copy elision),是C++语言标准中定义的编译优化技术。
当一个class类型的临时对象用于初始化同类型的对象时,复制初始化通常优化为直接初始化。
GCC的编译选项-fno-elide-constructors关闭复制省略。

返回值优化

RVO(Return Value Optimization,RVO),即避免函数返回过程触发复制 / 移动构造函数。根据返回的值是否是匿名对象,可以分为两类:

  • 具名返回值优化 NRVO (Named Return Value Optimization,NRVO)
  • 匿名返回值优化 URVO(Unknown Return Value Optimization,URVO )

二者的区别在于返回值是具名的局部变量还是无名的临时对象。

class Foo{
public:
	Foo(){std::cout<<"default"<<std::endl;}
	Foo(const Foo& rhs){std::cout<<"ctor"<<std::endl;}
	Foo(Foo&& rhs){std::cout<<"mtor"<<std::endl;}
};

Foo return_urvo_value() {
	return Foo();
}

Foo return_nrvo_value() {
	Foo local_obj;
	return local_obj;
}

int main(int argc, char const *argv[]) {
	Foo x = return_urvo_value();
	Foo y = return_nrvo_value();
	return 0;
}

无论是使用98标准,还是11标准,输出都是:
default
default
编译时加上“-fno-elide-constructors”选项,98下的输出是:
default
ctor
ctor
default
ctor
ctor
11下的输出是:
default
mtor
mtor
default
mtor
mtor
即使关闭复制省略,编译器也会优先选择mtor。

c++17强制编译器实现 URVO
在上面的例子中,Foo的mtor必须是可访问的,即移动构造函数没有加上=delete标志,也没有设置为private。到了c++17,即便禁止了移动构造函数,对象也能具有URVO的能力。

值传递优化

函数值传递传入右值时,也会发生 copy elision 行为,即使禁止编译器的 copy elision 行为,也是优先调用对象的mtor。

void pass_by_value(Foo foo) {}

int main() {
	pass_by_value(Foo{});
	Foo x;
	pass_by_value(std::move(x));
	return 0;
}

输出是:
default
default
mtor
关闭复制省略输出是:
default
mtor
default
mtor

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值