#include <iostream> #include <memory> using namespace std; //指针基础 void test1() { double d = 9.0; cout << "------1------" << endl; //取址操作 cout << &d << endl; cout << "------2------" << endl; //声明指针及指针赋值,读取指针 //应该把 double* 看作是一个复合类型来理解(类比数组,指针是基于其他类型的) double* dp; dp = &d; //也可以这样初始化 //double* dp = &d; // *dp 与 d 都代表值 9.0 ; dp 与 &d 都代表地址 cout << dp << endl; cout << *dp << endl; cout << "------3------" << endl; //对 dp 的理解,指针赋值 // dp 是指针变量,它也有自己的地址,下面输出指针 dp 的地址 cout << &dp << endl; /* 在地址 &dp 中储存的是 &d 的地址(一般用一个16进制数字来表示) 所以 dp 代表地址,本质是指针(变量); 加上间接值运算符*后, *dp 代表值,本质是一个double变量 */ //如果对 *dp 赋值,这样将修改地址为 dp 的内存区域储存的值 *dp = *dp + 1; cout << dp << endl; cout << *dp << endl; //变量 d 也指向地址为 dp 的内存区域 cout << d << endl; cout << "------4------" << endl; //错误的指针使用 /* int* wrongPoint; *wrongPoint = 233333; cout << wrongPoint << endl; cout << *wrongPoint << endl; */ /* 与上面的正确步骤相比较,这里少了给 wrongPoint 赋值地址的过程; 而地址 &wrongPoint 是什么值并不清楚,但程序都将其解释为地址,并将地址为 wrongPoint 的内存区域赋值为 233333 这将造成不可估量的恶劣后果 必须在使用 *wrongPoint 前,将 wrongPoint 初始化为一个合适的地址 */ cout << "------5------" << endl; //指针与数字 //上面提到地址一般用一个16进制数字来表示,但指针与数字 int 在c++是不一样的类型,不能直接赋值 //dp = 0xB8000000; //可以通过类型转换来 将 int 当作 地址 使用 dp = (double*)0xB8000000; cout << dp << endl; } //指针与动态内存 void test2() { cout << "------1------" << endl; //使用指针访问动态内存 /* 在test1中,指针只是作为变量的别名 变量是编译期分配的有别称的内存 而想要在运行期动态分配未命名的内存,只能通过指针来访问 下面使用 new 来动态分配内存 new 将找到大小合适存放 int 的内存,并返回该内存的地址 然后,需要将该地址赋值给相应的指针类型来使用 */ int* intPoint = new int; *intPoint = 1001; cout << intPoint << endl; cout << *intPoint << endl; cout << sizeof(*intPoint) << endl; cout << "------2------" << endl; //动态内存释放 //当动态内存使用完毕后,需要 delete 来释放,将该内存归还给内存池 //delete 只能用于 new 分配的内存,且同一块内存只能 delete 一次,即 new 与 delete 是配对使用的 delete intPoint; //注意 delete 真正作用的是内存快,而不是指针,指针并没有被删除,可以重新指向新的内存块 int* intPoint2 = new int; int* intPoint3 = intPoint2; *intPoint2 = 2; cout << intPoint2 << endl; cout << *intPoint3 << endl; delete intPoint3; cout << "after delete" << endl; //delete后,intPoint3不可用(指针的值已经改变),但intPoint2还是指向该内存,并且可访问,但是值已经没有意义了 cout << intPoint2 << endl; cout << *intPoint2 << endl; cout << intPoint3 << endl; //cout << *intPoint3 << endl; //重新分配有可能还是一样的地址,因为该地址已经归还到内存池了 intPoint2 = new int; cout << "renew" << endl; cout << intPoint2 << endl; cout << *intPoint2 << endl; } //数组与指针算术 void test3() { cout << "------1------" << endl; //创建动态数组,这里new返回第一个元素的地址 int* listIntP = new int[10]; //释放也要带 [] ,表示释放整个数组,而不是第一个元素 delete[] listIntP; cout << "------2------" << endl; //指针支持四种运算++、--、 + 、 - ;变化的量等于指针指向类型的字节数 int *intP = new int; cout << intP << endl; intP++; cout << intP << endl; intP = intP - 2; cout << intP << endl; cout << "------3------" << endl; //数组名通常被解释为第一个元素的地址。 int listInt[3] = {1, 2, 3}; cout << listInt << endl; cout << &listInt[0] << endl; cout << "------4------" << endl; //数组与指针基本等价,可以这样初始化一个指针 int* pointInt = listInt; //访问元素(在编译器里,pointInt[1] 看作是 *(pointInt + 1)) cout << pointInt[1] << ", " << listInt[1] << endl; cout << *(pointInt + 1) << ", " << *(listInt + 1) << endl; *(listInt + 1) = 4; pointInt[0] = 5; cout << listInt[0] << ", " << pointInt[1] << ", " << listInt[2] << endl; cout << "------5------" << endl; //数组与指针的区别 //指针可以修改值,而数组名是常量 pointInt++; cout << *pointInt << endl; //listInt++; //不合法 //使用sizeof,数组得到数组长度,指针是指针长度 cout << sizeof(pointInt) << endl; cout << sizeof(listInt) << endl; cout << "------6------" << endl; //c风格字符串也是数组,c++里 char数组名,char指针,字符串常量都被解释为字符串第一个字符的地址 char aa[20] = "aa"; const char* bb = "bb"; //cout对象接受到char地址时,会当作字符串打印,直至'\0' cout << aa << bb << "cc" << endl; //要输出地址,只能对地址类型转换 cout << (int*)aa << endl; } struct book { char name[20]; double price; }; //指针与动态结构 void test4() { book* ps = new book; //指针访问结构成员用 -> ,也可以用值加 . 来表示 char nameBook[20] = "sama"; strcpy_s(ps->name, nameBook); ps->price = 20.0; cout << (*ps).name << endl; cout << (*ps).price << endl; } /* 函数用数组名作为参数 */ /* 形式参数 arr[] 其实是一个指针,因为指针和数组名基本等价,可以把 arr 看作数组 该函数与以下声明等价 void printList(int* arr, int len) */ void printList(int arr[], int len) { cout << arr << endl; //输出长度不是数组的长度,因为arr是指针 cout << sizeof(arr) << endl; for (int i = 0; i < len; i++) { cout << arr[i] << endl; } } //二维数组的例子 /* 该函数与以下声明等价,该原型表示指向长度为4的数组的指针 void printList(int (*arr)[4], int len) */ void printList2(int arr[][4], int len) { cout << arr[1][1] << endl; } void test5() { int arr[] = { 1,2,3 }; cout << sizeof(arr) << endl; printList(arr, sizeof(arr) / sizeof(arr[0])); int arr2[2][4] = { {1,2,3,4}, {5,6,7,8} }; printList2(arr2, 2); } //二重(级)指针 void test6() { //存放指针地址的指针 int tt = 1; int* ttp = &tt; int** ttpp = &ttp; cout << tt << endl; cout << *ttp << endl; cout << **ttpp << endl; int t2 = 2; *ttpp = &t2; cout << *ttp << endl; cout << **ttpp << endl; } //函数指针 double pam(int a) { return a * 0.05; } void test7() { //函数指针原型 double (*pf)(int); //pam 即 方法pam的地址 pf = pam; //以下两种方法调用都是可以的 cout << (*pf)(2) << endl; cout << pf(1) << endl; } //智能指针 //自动执行回收的指针模板类,背后的思想是在类析构时调用delete class testPtr { public: testPtr(int a) { tag = a; cout << "new " << a << endl; }; ~testPtr() { cout << "delete " << tag << endl; }; int get() { return tag; }; void setShaerPtr(shared_ptr<testPtr> ptr1) { sPtr = ptr1; }; void setWeakPtr(weak_ptr<testPtr> ptr1) { wPtr = ptr1; }; weak_ptr<testPtr> getWeakPtr() { return wPtr; }; private: int tag; shared_ptr<testPtr> sPtr; weak_ptr<testPtr> wPtr; }; unique_ptr<testPtr> createUniquePtrObj(int a) { unique_ptr<testPtr> ptr(new testPtr(a)); return ptr; } void test8() { cout << "------1------" << endl; //在代码块结束后,智能指针unique_ptr将自动释放内存 { unique_ptr<testPtr> uptr(new testPtr(1)); //智能指针和普通指针一样可以使用解除引用和间接引用 cout << uptr->get() << endl; cout << (*uptr).get() << endl; } //智能指针不可用于非堆内存 //testPtr p(2); //unique_ptr<testPtr> uPtr2(&p); //unique_ptr的所有权是唯一的,一个对象只可以被一个unique_ptr拥有 //unique_ptr<testPtr> uptr3(new testPtr(3)); //unique_ptr<testPtr> uptr4; //uptr4 = uptr3; // 编译不通过 cout << "------2------" << endl; //这里的赋值是允许的,因为 createUniquePtrObj 的智能指针生命周期已经结束了,对象仍然只被一个智能指针持有 unique_ptr<testPtr> uptr5 = createUniquePtrObj(5); cout << uptr5->get() << endl; cout << "------3------" << endl; //可以通过move移交所有权,注意在移交所有权后,uptr6 变成了 nullptr unique_ptr<testPtr> uptr6, uptr7; uptr6 = createUniquePtrObj(6); cout << uptr6 << endl; uptr7 = move(uptr6); cout << uptr6 << endl; cout << uptr7 << endl; cout << uptr7->get() << endl; cout << "------4------" << endl; //与unique_ptr相对,shared_ptr可以共享所有权,shared_ptr通过引用计数管理对象的回收 { shared_ptr<testPtr> sptr1(new testPtr(7)); cout << sptr1.use_count() << endl; { shared_ptr<testPtr> sptr2 = sptr1; cout << sptr2.use_count() << endl; } cout << sptr1.use_count() << endl; } cout << "------5------" << endl; //shared_ptr存在环引用问题 { shared_ptr<testPtr> sptr2(new testPtr(8)); cout << sptr2.use_count() << endl; { shared_ptr<testPtr> sptr3 = sptr2; cout << sptr2.use_count() << endl; sptr2->setShaerPtr(sptr3); cout << sptr2.use_count() << endl; } cout << sptr2.use_count() << endl; //结束,testPtr(8)不会析构,此时 use_count = 1 } cout << "------6------" << endl; //引入weak_ptr避免环引用 { shared_ptr<testPtr> sptr4(new testPtr(9)); cout << "count:" << sptr4.use_count() << endl; { shared_ptr<testPtr> sptr5 = sptr4; cout << "count:" << sptr4.use_count() << endl; //setWeakPtr 入参是 weak_ptr,shared_ptr 可以自动类型转换为 weak_ptr sptr4->setWeakPtr(sptr5); cout << "count:" << sptr4.use_count() << endl; } cout << "count:" << sptr4.use_count() << endl; weak_ptr<testPtr> wptr = sptr4->getWeakPtr(); //控制对象回收,注释掉weak_ptr的行为会不一样 sptr4.reset(); cout << "count:" << sptr4.use_count() << endl; // weak_ptr 无法保证对象的有效性,一般用 lock() 获取shared_ptr对象,如果对象已经不可用,shared_ptr为空; // 也可以通过 expired() 获取是否已经销毁 shared_ptr<testPtr> sptrToWPtr = wptr.lock(); cout << sptrToWPtr << endl; if (sptrToWPtr) { cout << sptrToWPtr->get() << endl; } cout << wptr.expired() << endl; } cout << "------end------" << endl; } int main() { //test1(); //test2(); //test3(); //test4(); //test5(); //test6(); //test7(); test8(); return 0; }