c++ 拾遗
c++ 拾遗
1,左值和右值
左值是可以被修改的值,而右值则不能被修改,一般而言变量都是左值,而常数则是右值。
左值引用和右值引用
int a = 1;
int &b = a;
int &&c = 1;
此时b为左值引用,因为a是左值。而c则是右值引用,注意右值引用要用&&。
std::string function() {
return "hello world";
}
std::string&& a = function();
右值引用常用于接收函数将亡返回值,节省开销。 此外,右值用于移动语义和完美转发(后面填坑)。
2,指针
关于malloc,free以及new,delete
malloc和free是c语言的库函数,而new和delete是c++的运算符。 malloc和free是函数,new和delete是运算符。 malloc直接分配空间而new是先分配空间再调用构造函数。
指针的情况
指针的值(即地址)应属下列4种状态之一 1.指向一个对象。 2.指向紧邻对象所占空间的下一个位置。(end迭代器) 3.空指针,意味着指针没有指向任何对象。 4.无效指针,也就是上述情况之外的其他值。 试图拷贝或以其他方式访问无效指针的值都将引发错误。编译器并不负责检査此类错误,这一点和试图使用未经初始化的变量是一样的,访问无效指针的后果无法预计,因此程序员必须清楚任意给定的指针是否有效。尽管第2种和第3种形式的指针是有效的,但其使用同样受到限制;显然这些指针没有指向任何具体对象,所以试图访问此类指针(假定的)对象的行为不被允许。如果这样做了,后果也无法预计。
万能指针
void *p;
int a=1;
p=&a;
*((int*)p);
万能指针不受类型限制,可以指向任意类型的对象。但是解引用时则必须进行类型转换
3,const
需要注意const只在本文件内有效,有点像#define的效果,编译器会把const替换成具体的值。多个文件如果重复定义const,那么它们也是独立的值,互不影响。而extenrn则是在其他文件中定义的const,需要在本文件中使用。可以避免多开销。
double pi=3.14;
//int &a=pi; //错误,类型不匹配
const int &a=pi; //正确
其实在上述情况编译器进行了隐式转换,把pi转换成了int类型。只有constt才可以这样。
重要的一点要区分以下两个:
int a=5;
const int* p=&a;//1.
int const* p=&a;//2.
第一个是表示不能通过p解引用来修改a的值,但是p存储的地址可以被修改即可以让p指向其他变量。而第二个则表示p存储的地址不能被修改,即不能指向其他变量了,但可以通过解引用修改p指向的值。
const int* const p=&a;//3.
第三种情况最惨,p存储的地址和p指向的值都不能被修改。属于是集百家之短了。
4,auto和decltype
auto是c++11引入的关键字,用于自动推导变量的类型。
auto a=1;
auto b=1.0;
auto c='a';
auto d="hello world"; ###
auto的const auto会忽略掉顶层const,保留底层const。 const int a=1;
auto b=a; //b的类型是int ###
auto的引用 auto会忽略掉引用。 int a=1;
auto &b=a; //b的类型是int ### auto的数组
auto会忽略掉数组的维度。 int a[10];
auto b=a; //b的类型是int* ### auto的指针
auto会忽略掉指针的星号。 int *a;
auto b=a; //b的类型是int ### decltype
decltype是c++11引入的关键字,用于获取变量的类型。 int a=1;
decltype(a) b=a; //b的类型是int ###
decltype的const decltype会保留顶层const。 const int a=1;
decltype(a) b=a; //b的类型是const int ###
decltype的引用 decltype会保留引用。 int a=1;
decltype(a) &b=a; //b的类型是int& ### decltype的数组
decltype会保留数组的维度。 int a[10];
decltype(a) b=a; //b的类型是int[10] ### decltype的指针
decltype会保留指针的星号。 int *a;
decltype(a) b=a; //b的类型是int*
5,结构体
c++中的结构体十分的灵活,基本上和类的功能和操作一样了,唯一的区别就是结构体的成员默认是public的,而类的成员默认是private的。实际用法上,结构体用于存储数据,而类用于封装数据和操作。、
6,仿函数
又称函数对象,是一个类,重载了()运算符,使得该类的对象可以像函数一样调用。
class MyClass {
public:
void operator()(int a, int b) {
cout << a + b << endl;
}
}
MyClass myClass;
myClass(1, 2); //输出3 优点: 1. 可以像函数一样调用。 2. 可以在类中保存状态。 3.
可以作为函数参数。 4. 可以作为函数返回值。 5. 可以作为模板参数。 6.
可以作为STL算法的参数。
