经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » 程序设计 » C++ » 查看文章
C++学习笔记之指针引用 - time-flies
来源:cnblogs  作者:time-flies  时间:2021/5/24 10:58:35  对本文有异议

指针

指针定义

指针定义的基本形式:指针本身就是一个变量,其符合变量定义的基本形式,它存储的是值的地址。对类型T,T是“到T的指针”类型,一个类型为T的变量能保存一个类型T的对象的地址
如:

  1. int a=112;
  2. float c=3.14;
  3. int* d=&a;
  4. float* e=&c;
  5. cout << d << endl; cout << e << endl;
  6. cout << (*d) << endl; cout << (*e) << endl;

通过一个指针访问它所指向地址的过程称为间接访问(indirection)或者引用指针(dereferencing the point);这个用于执行间接访问的操作符是单目操作符*:

  1. cout<<(*d)<<endl;
  2. cout<<(*e)<< endl;

左值与右值

概念:

  • 编译器为其单独分配了一块存储空间,可以取其地址的,左值可以放在赋值运算符左边;
  • 右值指的是数据本身,不能取到其自身地址,右值只能赋值运算右边;

具体分析:

  • 左值最常见的情况如函数和数据成员的名字;
  • 右值是没有标识符、不可以取地址的表达式,一般也称之为“临时对象"。

比如:a=b+c; &a是允许的操作,而&(b+c)不能通过编译,因此a是一个左值,而(b+c)是一个右值;

指针数组与数组指针

指针的数组(array of pointers)与数组的指针(a pointer to an array):

  • 指针的数组 T t []*:运算符和T结合,定义数组的元素为T指针类型。
  • 数组的指针 T (*t) []:*运算符和t结合,定义变量t为指针变量。
  1. int* a[4]; // array of pointers 指针的数组
  2. int (*b) [4]; // a pointer to an array 数组的指针
  3. // 输出
  4. cout << *(a[0]) << endl;
  5. cout << (*b)[0] << endl;

const与指针

const pointerpointer to const例子:

  1. char strHelloworld[]={"helloworld"};
  2. char const * pStr1="helloworld"; //和const char* pStr1等效
  3. char * const pStr2="helloworld";
  4. char const * const pStr3="helloworld";
  5. pStr1=strHelloworld;
  6. //pStr2=strHelloworld; //pStr2不可改
  7. //pStr3=strHelloworld; //pStr3不可改

关于const修饰的部分:

  • 看左侧最近的部分;
  • 如果左侧没有,则看右侧;

指针的指针

指向指针的指针例子:

  1. int a=123;
  2. int* b=&a;
  3. int** c=&b;

*操作符具有从右向左的结合性,上面取值规则如下:

  • **这个表达式相当于*(*c),必须从里向外逐层求值;
  • *c得到的是c指向的位置,即b;
  • **c相当于*b,得到变量a的值;

NULL指针

NULL指针:一个特殊的指针变量,表示不指同任何东西。

  1. int* a=NULL;

NULL指针给了一种方法,来表示特定的指钍目前未指向任何东西,使用的注意事项:

  • 对于一个指针,如果已经知道将被初始化为什么地址,那么请赋给它这个地址值,否则适把它设置为NULL
  • 在对一个指针进行间接引用前,请先判断这个指针的值为否为NULL
  • 没有初始化的,不用的或者超出范围的指针请把值置为NULL

内存泄漏(Memory Leak)问题

内存泄漏问题:指程序中己动态分配的维内存由于某种原因程序未释放或无法释,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。

内存泄漏发生原因和排查方式:

  • 内存泄漏主要发生在堆内存分配方式中,即“配置了内存后,所有指向该内存的指针都遗失了”。
  • 因为内存泄漏属于程序运行中的问题,无法通过编译识别,所以只能在程序运行过程中来判别和诊断
  1. while (true)
  2. {
  3. int* wp1 = new int(10); //内存泄漏
  4. }

智能指针

C++中推出了四种常用的智能指针:

  • unique ptr:专属所有权,管理的内存只能被一个对象持有,不支持复制和赋值,可以使用std:move()进行控制所有权的转移。
  1. auto w = std::make_unique<int>(10);
  2. cout << *(w.get()) << endl; // 10
  3. //auto w2 = w; // 编译错误如果想要把 w 复制给 w2, 是不可以的。
  4. auto w2 = std::move(w); // w2 获得内存所有权,w 此时等于 nullptr
  5. cout << ((w.get() != nullptr) ? (*w.get()) : -1) << endl; // -1
  6. cout << ((w2.get() != nullptr) ? (*w2.get()) : -1) << endl; // 10
  • shared ptre通过一个引用计数共享一个对象,当引用计数为0时,该对象没有被使用,可以进行析构。
  1. auto wA = shared_ptr<int>(new int(20));
  2. {
  3. auto wA2 = wA;
  4. cout << ((wA2.get() != nullptr) ? (*wA2.get()) : -1) << endl; // 20
  5. cout << ((wA.get() != nullptr) ? (*wA.get()) : -1) << endl; // 20
  6. cout << wA2.use_count() << endl; // 2
  7. cout << wA.use_count() << endl; // 2
  8. }
  9. //cout << wA2.use_count() << endl;
  10. cout << wA.use_count() << endl; // 1
  11. cout << ((wA.get() != nullptr) ? (*wA.get()) : -1) << endl; // 20
  12. // move 语法,意味着放弃了对内存的所有权和管理
  13. auto wAA = std::make_shared<int>(30);
  14. auto wAA2 = std::move(wAA); // 此时 wAA 等于 nullptr,wAA2.use_count() 等于 1
  15. cout << ((wAA.get() != nullptr) ? (*wAA.get()) : -1) << endl; // -1
  16. ccout << wAA.use_count() << endl; // 0
  17. cout << wAA2.use_count() << endl; // 1
  • weak ptr:被设计为与shared_ptr共同工作(避免循环引用shared_ptr导致的内存泄露),用一种观察者模式工作,只对shared ptr进行引用而不改变其引用计数,当被观察的 shared ptr失效后相应的weak ptr也相应失效。
  1. struct AW
  2. {
  3. shared_ptr<BW> pb;
  4. ~AW() { cout << "~AW()" << endl; }
  5. };
  6. struct BW
  7. {
  8. weak_ptr<AW> pa; //此处改为shared_ptr则会发生内存泄漏(循环引用)
  9. ~BW() { cout << "~BW()" << endl; }
  10. };
  11. void Test()
  12. {
  13. cout << "Test shared_ptr and shared_ptr: " << endl;
  14. shared_ptr<A> tA(new A());
  15. shared_ptr<B> tB(new B());
  16. cout << tA.use_count() << endl; // 1
  17. cout << tB.use_count() << endl; // 1
  18. tA->pb = tB;
  19. tB->pa = tA;
  20. cout << tA.use_count() << endl; // 2
  21. cout << tB.use_count() << endl; // 2
  22. }
  23. void Test()
  24. {
  25. cout << "Test weak_ptr and shared_ptr: " << endl;
  26. shared_ptr<AW> tA(new AW());
  27. shared_ptr<BW> tB(new BW());
  28. cout << tA.use_count() << endl; // 1
  29. cout << tB.use_count() << endl; // 1
  30. tA->pb = tB;
  31. tB->pa = tA;
  32. cout << tA.use_count() << endl; // 1
  33. cout << tB.use_count() << endl; // 2
  34. }
  35. int main()
  36. {
  37. Test();
  38. return 0;
  39. }
  • auto_ptr:在拷贝/赋值过程中,会直接剥夺指针对原对象对内存的控制权(C++11中已经废弃的,在C++17中被正式删除)。

引用

C++的引用是一种特殊的指针,不允许修改的指针,参考 C++:引用的简单理解

注:C++中类的引用也需要显式定义,C#中除了值类型则全是引用类型,注意区别。

使用指针有空指针、野指针、不知不觉改变了指针的值却继续使用的问题,使用引用则:

  • 不存在空引用;
  • 必须初始化;
  • 一个引用永远指向它初始化的那个对象;
  1. int x = 1, x2 = 3;
  2. int& rx = x;
  3. rx = 2;
  4. cout << x << endl; //2
  5. cout << rx << endl; //2
  6. rx = x2;
  7. cout << x << endl; //3
  8. cout << rx << endl; //3

有了指针为什么还需要引用?
Bjarne Stroustrup的解释:为了支持函数运算符重载

有了引用为什么还需要指针?
Bjarne Stroustrup的解释:为了兼容C语言

关于函数传递参数类型的说明:

  • 内置基础类型(如int,double等)而言,在函数中传递时pass by value更高效;
  • 对OO面向对象中自定义类型而言,在函数中传递时pass by reference to const更高效;

原文链接:http://www.cnblogs.com/timefiles/p/CppStudyNotesPointerReference.html

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号