c++的三种变量语义
Posted zkccpro
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++的三种变量语义相关的知识,希望对你有一定的参考价值。
c++的三种变量语义
1. 值语义变量
这。。。其实我们大一学c语言的时候都知道它是啥!但当时的自己可能并不理解值语义变量到底意味着啥???直到我反复研读primer、mordern c++。再结合自己写代码,慢慢才对这个抽象有了更深的认识。
值语义变量,比如:
int a=0;
std::vector<int> arr;
class A
//some functions...
Big* big_;//这是一个占用很大空间的类
;
A aa;
看似这很简洁,就是不带引用和指针修饰的变量嘛!他们的存储空间开辟在栈上,声明周期由栈管理,不用担心内存泄漏什么的问题。这听起来很好,但有一个最大的问题:拷贝!
//承接上面的代码
std::vector<int> arr1=arr;
A bb(aa);
这会导致什么呢?没错,就是深拷贝的代价。以上两句分别触发了c=和c-ctor。为了保证释放指针的安全性,拷贝构造将会使用深拷贝的写法。(std::shared_ptr是一种避免深拷的方法,但shared本身也会带来性能损耗呀!)如果Big
类对象、arr
很大的话,深拷显然很不划算。。这一点在函数实参形参传递时很常见!(返回值会有RVO优化一般不用担心性能问题。)
2. 对象语义
对象这个概念严格来说应该是java里的吧。。对象语义的出现就是为了防止深拷贝带来性能损耗的。原理也很简单,用两个指针指向一片空间,共用之就行了。当然问题也是有的,那就是释放的时候要记着只能释放它们其中一个。。因此,c++陆续推出了引用、智能指针来包装对象语义。
int a=0;
int& ra=a;
int* pa=&a;
引用和指针都算作对象语义的实现。和java的对象语义不同,c++并不是严格地规定对象的空间必须在堆上。对象指向栈上或者其他什么地方也未尝不可。(只要你能玩明白就行。。。)
引用和智能指针分别有啥优点这里就不展开啦,之前讨论过了。这里的重点是,对象语义可以避免深拷带来的性能损耗。
3. 右值语义
右值语义是c++11之后新推出的一种语义,和它紧密联系的就是移动语义了。(但移动语义不是变量语义昂,是一种行为语义)和右值对应的就是左值,左值语义一般来说包括以上两种:值变量与对象变量。
右值语义的定义是很自然的:想象一下,以上两种变量的生命周期都是较长一段时间的——不论在栈上或是堆上。那在高级语言中该不该有一种变量的生命只存在于一个语句呢(暂时的)?肯定是有的啊!比如:
int a=2;//这句中的“2”,在汇编里叫“立即数”吧!
class A
//something...
static void static_func();
;
A().static_func();//c++中的临时变量:“A()”
int&& rra=std::move(a);//c++11中,我们可以自己“构造”一个右值变量了
在语句:int&& rra=std::move(a);
中,a是std::move(a)
这个表达式被认为是一个右值(即返回值是右值),但rra
却是一个左值,被称为右值引用。这一点必须在本节搞清楚!所以说,右值引用的作用也很简单,就是可以”接住“转瞬即逝的右值,将快死掉的右值附到一个持久的左值上,留作后用。这个左值就是右值引用。
是不是很清晰呢?这些这些知识在通读primer之后就可以搞清楚了,算是很基本的用法。但下一节要讲的std::move和std::forward,貌似就没这么容易懂了!(反正我看了primer是没搞明白)想搞清楚这二者的区别,本节的内容是基础,必须彻底明白。
以上是关于c++的三种变量语义的主要内容,如果未能解决你的问题,请参考以下文章