定制网站和模板建站哪个好用,php做的网站模版,版式设计网站,天津建设工程协会网站仿写实现move函数
一、值的类型 1.左值
描述#xff1a;能够取地址的值成为左值
int a 10;
const int b 15;
int *pa a;
const int *pb b;2.纯右值
描述#xff1a;赤裸裸的字面值 eg(false , 3 , 12.23等)
int a 13;
int *p a; //取a的地址
int …仿写实现move函数
一、值的类型 1.左值
描述能够取地址的值成为左值
int a 10;
const int b 15;
int *pa a;
const int *pb b;2.纯右值
描述赤裸裸的字面值 eg(false , 3 , 12.23等)
int a 13;
int *p a; //取a的地址
int *ptr 13; //错误13是一个字面量无法取地址 如字面常量 103 12.23 nullptr不可以取地址 称为为纯右值。
3.将亡值
描述表达式的运行或计算过程中所产生的临时量或临时对象称之为将亡值临时量有可能是字面值也有可能是一个不具名的对象。
算术表达式ab …逻辑表达式a || b …比较表达式a ! b …取地址表达式b)等产生的计算结果相当于字面量实际存储在 cpu的寄存器中 因为计算结果是字面量所以为纯右值。
如图
因为c是面向对象的所以 i 和 i 是不一样的 i 相当于 i i 1 所以 不会产生临时变量 而 i不同它相当于 将 i 拷贝一份当做副本然后将原来的 i 进行加 1 操作最后将 副本 的值返回。 副本是不具名的所以是 将亡值而 返回的值是 字面量 所以 i 为纯右值 。
不具名对象如图 编译后会报错 test.cpp(17): error C2102: “”要求左值,。
因为 Int(13) 程序运行过程中所产生了不具名对象将亡值。 不可以取地址, 所以Int(13)错误 。
int fun()
{int value 10;return value;
}
int main()
{int i 0;int a 1;i a b;i;b;a fun(); //返回时在主栈帧中构造临时量是将亡值纯右值。return 0;
}流程图 图 2.2 当fun函数return 时 其栈帧空间会被回收此时先在主栈帧中创建一个将亡值对象(xvalue) 将返回的值赋给将亡值回到主函数栈帧中会再将将亡值对象的值赋给 a.
二、引用
基本原则
1.声明引用的时候必须初始化且一旦绑定不可把引用绑定到其他对象即引用必须初始化不能对引用重定义
2.对引用的一切操作就相当于对原对象的操作
1.引用与函数重载
void fun(int val)
{cout LeftRef endl;
}
void fun(const int val)
{cout Const LeftRef endl;
}
void fun(int val)
{cout RightRef endl;
}
int main()
{int a 10; const int d 15;int f 12; //右值引用f是具名右值引用编译器会将已命名的右值引用视为左值//int g f; // error,f为具名右值fun(a); fun(d);fun(f);fun(13);return 0;
}运行结果 结论
1.int a 10; 右值引用 a 是具名右值引用。
2.编译器会将已命名的右值引用视为左值,所以不能 int b a;
2.函数返回值
int func()
{int x 10;coutx: endl;return x;
}int main()
{int a func();//int b func(); // error; func返回值为右值.const int c func(); cout c: c endl;int d func();cout d: d endl;return 0;
}
运行结果 结论1.函数返回值为将亡值右值
2.常性左值引用为万能引用可以接受右值
3.自定义类
class Int
{int val;
public:Int(int x 0) :val(x){cout Create Int: this endl;}Int(const Int it) :val(it.val){cout this Copy Create Int: it endl;}Int(Int it) :val(it.val){it.val 0;cout this Move Create Int: it endl;}Int operator(const Int it){if (this it) return *this;val it.val;cout this it endl;return *this;}Int operator(Int it){if (this it) return *this;val it.val;it.val 0;cout this it endl;return *this;}~Int() { cout Destroy Int: this endl; }
};Int func(int x)
{Int tmp(x);return tmp;
}int main()
{Int a func(1);cout -------------------- endl;Int x(0);cout -------------------- endl;x func(2);cout -------------------- endl;//Int b func(3);const Int c func(4);cout -------------------- endl;Int d func(5);cout -------------------- endl; Int f(a);cout -------------------- endl;return 0;
}运行结果 结论
1.通过右值引用比之前少了一次移动构造和一次析构原因在于右值引用绑定了右值让临时右值的生 命周期延长了 主栈帧里创建的不具名对象(将亡值)
2.函数返回值构建过程和之前分析的一样 图 2.2
三、std::move的实现
原理
本质上是将左值强制转换为右值引用调用对象的移动构造和移动赋值函数实现对资源的转移。
优点
当一个对象内部有较大的堆内存或者动态数组时进行深拷贝会占用cpu资源而浅拷贝释放资源时会造成对堆区进行重复释放导致非法访问。使用move()语义可以提高性能
使用范围
move 对于拥有形如对内存、堆区等资源的成员的对象有效
1.未定义的引用类别 函数模板中
template class _Ty
void fun(_Ty x) //未定义的引用类型它必须被初始化它是左值还是右值引用取决于它的初始化
{int z 10;_Ty y z;
}
int main()
{int a 1;const int b 2;int c a;const int d b;fun(10); fun(a);fun(b);fun(c);fun(d);return 0;
}fun(a),fun© x 的类型为 int y的类型为 int;
fun(b),fun(d)x的类型为 const int ,y的类型为const int;
fun(10)x的类型为 int , y 的类型为 int,不具有引用
结论 _Ty 与左值普通左值引用结和_Ty为左值引用 _Ty 与左值常引用结合_Ty为左值常性引用 _Ty 与右值结合时_Ty只保留类型不具有引用属性 _Ty 不会破坏掉 对象的const属性
实现流程
1.我们需用取出对象的引用属性
template class _Ty
struct my_remove_reference
{using type _Ty;my_remove_reference(){cout _Ty endl;}
};
template class _Ty
struct my_remove_reference_Ty
{using type _Ty;my_remove_reference(){cout _Ty endl;}
};
template class _Ty
struct my_remove_reference_Ty
{using type _Ty;my_remove_reference(){cout _Ty endl;}
};2.加入适配器使其具有普适性
template class _Ty
using my_remove_reference_t typename my_remove_reference_Ty::type;3.转换为右值
template class _Ty
my_remove_reference_t_Ty my_move(_Ty x)
{return static_castmy_remove_reference_t_Ty(x);
}
典型错误使用c语言中的强制类型转换
template class _Ty
my_remove_reference_t_Ty my_move(_Ty x)
{ return (my_remove_reference_t_Ty)x; //error,不能使用c语言中的强制类型转换
}因为常性对象的资源是不能进行移动修改的而强制类型转换会破坏这一平衡点而c的静态类型转换刚好不会去掉const属性。