(P87+P88)boost智能指针:boost智能指针,scoped_ptr ,shared_ptr,weak_ptr,scoped_array/shared_array,pimpl技法

news/2024/4/19 1:59:24

文章目录

    • 1.boost智能指针
    • 2.scoped_ptr
    • 3.shared_ptr
    • 4.weak_ptr
    • 5.scoped_array/shared_array
    • 6.PIMPL技法

1.boost智能指针

  • 智能指针是利用RAII(Resource Acquisition Is Initialization:资源获取即初始化)来管理资源
    在构造函数中对资源初始化,在析构函数中对资源释放

  • 智能指针的本质思想是:
    (1)将堆对象的生存期用栈对象(智能指针)来管理,当new一个堆对象的时候,立刻用智能指针来接管。具体做法是:在构造函数进行初始化(用一个指针指向堆对象),在析构函数中调用delete来释放堆对象。
    (2)由于智能指针本身是一个栈对象,他的作用域结束的时候,会自动调用析构函数,从而调用了delete释放了堆对象

  • 常用的智能指针
    scoped_ptr对象既不能被拷贝,也不能被赋值
    intrusive_ptr不常用
    waek_ptr主要是解决循环引用的问题
    在这里插入图片描述

  • boost库在vs2008的配置,下载boost库后
    在这里插入图片描述

2.scoped_ptr

  • 智能指针本身是栈上对象
  • eg:P87\01.cpp
#include <boost/scoped_ptr.hpp>
#include <iostream>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}
};int main( void)
{cout <<  "Entering main ..." << endl;{//X堆对象,由智能指针栈对象pp来管理//智能指针栈对象pp销毁的时候,他所管理的堆对象也就跟着销毁了boost::scoped_ptr<X> pp( new X);//boost::scoped_ptr<X> p2(pp); //Error:所有权不能转移}cout <<  "Exiting main ..." << endl;return  0;
}
  • 测试:
    在这里插入图片描述

  • 断点:

        boost::scoped_ptr<X> pp( new X);

构造函数:px指针接管
在这里插入图片描述
析构函数:
在这里插入图片描述
typedef那两行是判定T是否是完整类型
在这里插入图片描述

 //boost::scoped_ptr<X> p2(pp); //Error:所有权不能转移

拷贝构造和=号运算符都是私有的
在这里插入图片描述

3.shared_ptr

  • 内部维护了一个引用计数reference
  • eg:P87\02.cpp
#include <boost/shared_ptr.hpp>
#include <iostream>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}
};int main( void)
{cout <<  "Entering main ..." << endl;boost::shared_ptr<X> p1( new X);cout << p1.use_count() << endl;//输出引用计数boost::shared_ptr<X> p2 = p1;//用p1对象初始化p2对象,调用拷贝构造函数,相当于共享一个对象//boost::shared_ptr<X> p3;//p3 = p1;cout << p2.use_count() << endl;//其值等于p1.use_count()p1.reset();//表示置空,显式的将引用计数-1,也可以不用,等程序结束的时候会进行的,因为是智能指针是栈对象嘛cout << p2.use_count() << endl;p2.reset();cout <<  "Exiting main ..." << endl;return  0;
}
  • 测试:
    在这里插入图片描述
  • 断点:
    boost::shared_ptr<X> p1( new X);

在这里插入图片描述
接着调用class X的构造函数,略;
接着调用shared_ptr的构造函数,px是一个指针,pn是管理引用计数的
在这里插入图片描述
在这里插入图片描述
要调用构造函数,对象成员的构造函数要先调用,会调用shared_count的构造函数
在这里插入图片描述
在这里插入图片描述
F11
在这里插入图片描述
F11,调用其构造函数
在这里插入图片描述
F11,
在这里插入图片描述
会调用基类的构造函数,强引用use_count_,弱引用weak_count_初始化为1
在这里插入图片描述

  • 断点:
    cout << p1.use_count() << endl;//输出引用计数

在这里插入图片描述
F11
在这里插入图片描述

  • 断点位置如下:直接在boost库中打断点
目的是看boost::shared_ptr<X> p2 = p1;调用默认拷贝构造函数后,引用计数怎么到这里++

引用计数+1的操作位置,这是原子性的自增操作,shared_ptr是线程安全的,内部的引用计数是线程安全的
在这里插入图片描述
shared_ptr没有提供拷贝构造函数,是编译器提供的默认拷贝构造函数
在这里插入图片描述
双击是看不到默认的拷贝构造函数
在这里插入图片描述
从上往下看,还看到还会调用shared_count的拷贝构造函数,因为shared_count是其内部所持有的对象
在这里插入图片描述
注意:shared_count const & r这里的r是一个常量,修改常量的值这里有个技巧:
pi_和r.pi指针指向同一个地方,现在堆pi_进行修改,对pi_所做的修改就是对r.pi所做的修改,这样就成功的将常量r进行了修改
在这里插入图片描述

const 常量
const int n = 100;
p = &n;
*p = 300;是可以修改常量的值的
  • eg:P87\03.cpp
#include <boost/shared_ptr.hpp>
#include <iostream>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}
};int main( void)
{cout <<  "Entering main ..." << endl;boost::shared_ptr<X> p1( new X);cout << p1.use_count() << endl;//输出引用计数boost::shared_ptr<X> p2 = p1;//用p1对象初始化p2对象,调用拷贝构造函数,相当于共享一个对象boost::shared_ptr<X> p3;p3 = p1;//等号运算符cout << p2.use_count() << endl;//其值等于p1.use_count()p1.reset();//表示置空,显式的将引用计数-1,也可以不用,等程序结束的时候会进行的,因为是智能指针是栈对象嘛cout << p2.use_count() << endl;p2.reset();cout <<  "Exiting main ..." << endl;return  0;
}
  • 测试:
    在这里插入图片描述
  • 断点:
     p3 = p1;

this_type会调用拷贝构造函数,并把它交换给this;即=运算符也是借助拷贝构造使得引用计数+1的;
在这里插入图片描述
在这里插入图片描述

  • auto_ptr不能放置在vector中,但是shared_ptr是可以放置在vector中的。
  • eg:P87\04.cpp
#include <boost/shared_ptr.hpp>
#include <iostream>
#include <memory>
#include <vector>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}
};int main( void)
{//编译失败// vector<auto_ptr<X> > v;// auto_ptr<X> p(new X);// v.push_back(p);//boost::shared_ptr<X>是可以放到vector中的vector<boost::shared_ptr<X> > v;boost::shared_ptr<X> p(new X);v.push_back(p);//push_back内部会构造一个shared_ptr对象,与p一样,所以输出为2cout<<v.use_count<<endl;//2个对象都引用了X//当p对象销毁,向量v中的对象也被销毁的时候,引用计数减为0,则堆对象X自动被销毁return  0;
}
  • 测试:
    编译失败
    在这里插入图片描述
    push_back时会调用=号运算符
    在这里插入图片描述
    auto_ptr不能放置在vector中的原因是:
    auto_ptr的=号运算符如下:这里要求是非const的的引用,在做=运算时,_Right.release()所有权要发生转移,_Right变量的内容会发生改变
    在这里插入图片描述
    而vector里面的=号运算符,_Val是一个常量,是不能被更改的,即上面的_Right.release()是不能被更改的,不符合上面的auto_ptr<_Other>& _Right这里的接口,所以编译出错。
    在这里插入图片描述
    在这里插入图片描述
    编译成功的原因:接口是const的,符合接口。const变量不代表不能被更改,shared_ptr内部通过指针的方式来修改常量,但是接口保留const。
    所以,auto_ptr基本都不用了。
    在这里插入图片描述
  • shared_ptr注意事项
    详见:http://www.boost.org/doc/libs/release/libs/smart_ptr/shared_ptr.htm
//实参传递到形参scoped_ptr<T>控制权不能转移,不能像下面这么用,根本就是错的
void f(shared_ptr<int>, int);
int g();void ok()
{//这是没有内存泄漏的//f(p, g());会调用拷贝构造函数,形参与p共享对象,他俩都结束时,引用计数减为0//new int(2)对象会销毁shared_ptr<int> p(new int(2));f(p, g());
}void bad()
{//可能存在内存泄漏//如果new int(2)构造,接着g()构造,此时在g()中抛出异常//没有调用shared_ptr的构造函数//那么new int(2)就没有被shared_ptr所接管,会造成内存泄漏//如果编译器的执行顺序是:从右往左,那么就不会,所以也要看编译器f(shared_ptr<int>(new int(2)), g())
}

4.weak_ptr

  • 循环引用问题
    在这里插入图片描述

  • eg:P87\05.cpp

#include  <boost/shared_ptr.hpp>
#include  <iostream>
using   namespace  std;class  Parent;
class  Child;
typedef  boost::shared_ptr<Parent>  parent_ptr;
typedef  boost::shared_ptr<Child>  child_ptr;class  Child
{
public:Child(){cout  <<   "Child  ..."  <<  endl;}~Child(){cout  <<   "~Child  ..."  <<  endl;}parent_ptr  parent_;//持有一个Parent类的智能指针对象
};class  Parent
{
public:Parent(){cout  <<   "Parent  ..."  <<  endl;}~Parent(){cout  <<   "~Parent  ..."  <<  endl;}child_ptr  child_;//持有一个Child的智能指针对象
};int  main( void)
{parent_ptr  parent( new  Parent);child_ptr  child( new  Child);//Parent父亲对象中的孩子指向孩子对象parent->child_  =  child;//孩子对象引用计数=2//Child孩子对象中的父亲指向父亲对象child->parent_  =  parent;//父亲对象引用计数=2//这样父亲对象和孩子对象都无法正常释放return   0;
}
  • 测试:析构函数都没调用
    在这里插入图片描述

  • 解决办法1:手动打破循环引用(不好,还不如用原生指针)

  • eg:P87\06.cpp

#include  <boost/shared_ptr.hpp>
#include  <iostream>
using   namespace  std;class  Parent;
class  Child;
typedef  boost::shared_ptr<Parent>  parent_ptr;
typedef  boost::shared_ptr<Child>  child_ptr;class  Child
{
public:Child(){cout  <<   "Child  ..."  <<  endl;}~Child(){cout  <<   "~Child  ..."  <<  endl;}parent_ptr  parent_;//持有一个Parent类的智能指针对象
};class  Parent
{
public:Parent(){cout  <<   "Parent  ..."  <<  endl;}~Parent(){cout  <<   "~Parent  ..."  <<  endl;}child_ptr  child_;//持有一个Child的智能指针对象
};int  main( void)
{parent_ptr  parent( new  Parent);child_ptr  child( new  Child);//Parent父亲对象中的孩子指向孩子对象parent->child_  =  child;//孩子对象引用计数=2//Child孩子对象中的父亲指向父亲对象child->parent_  =  parent;//父亲对象引用计数=2//这样父亲对象和孩子对象都无法正常释放parent->child_.reset();//让孩子对象的引用计数变成1,打破循环引用//child智能指针对象销毁时,当前引用计数从1->0,所以Child对象被销毁,且Child对象//又持有parent_,此时parent_引用计数减为1,当Parent对象销毁时,parent_计数从1->0,所以///Parent会被销毁return   0;
}
  • 测试:
    在这里插入图片描述

  • 解决办法2:使用weak_ptr解决(自动非人工)
    在这里插入图片描述
    (1)强引用,只要有一个引用存在,对象就不能释放
    (2)弱引用,并不增加对象的引用计数(实际上是不增加use_count_, 会增加weak_count_);但它能知道对象是否存在
    如果存在,提升为shared_ptr(强引用)成功;
    如果不存在,提升失败;
    (3)通过weak_ptr访问对象的成员的时候,要提升为shared_ptr
    (4)shared_ptr是强引用
    weak_ptr是弱引用,即使对象销毁了,可能弱引用还存在,此时继续提升,可能会失败。

  • eg:

  • 测试:
    在这里插入图片描述

  • eg:P87\08.cpp

#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}void Fun(){cout <<  "Fun ..." << endl;}
};
int main( void)
{//weak_ptr通常要与shared_ptr配合使用boost::weak_ptr<X> p;//定义一个若指针对象引用{boost::shared_ptr<X> p2( new X);cout << p2.use_count() << endl;//=1p = p2;cout << p2.use_count() << endl;//p2是强引用,引用计数=1//要访问X中的数据成员,首先要将弱引用p提升为shared_ptr//弱引用没有重载->指针运算符,强引用有的boost::shared_ptr<X> p3 = p.lock();if (!p3)cout<<"object is destroyed"<<endl;//p.lock()看下能否提升,lock()表示提升,也表示锁定对象,防止被销毁elsep3->Fun();}//p2引用的对象会被销毁,因为引用计数=1boost::shared_ptr<X> p4 = p.lock();if (!p4)cout<<"object is destroyed"<<endl;elsep4->Fun();return  0;
}
  • 测试:
    在这里插入图片描述

5.scoped_array/shared_array

  • 针对于数组
  • eg:P87\10.cpp
#include <boost/shared_ptr.hpp>
#include <boost/weak_ptr.hpp>
#include <boost/scoped_array.hpp>
#include <boost/scoped_ptr.hpp>
#include <iostream>
using  namespace std;class X
{
public:X(){cout <<  "X ..." << endl;}~X(){cout <<  "~X ..." << endl;}void Fun(){cout <<  "Fun ..." << endl;}
};
int main( void)
{//weak_ptr通常要与shared_ptr配合使用boost::weak_ptr<X> p;//定义一个若指针对象引用{boost::shared_ptr<X> p2( new X);cout << p2.use_count() << endl;//=1p = p2;cout << p2.use_count() << endl;//p2是强引用,引用计数=1//要访问X中的数据成员,首先要将弱引用p提升为shared_ptr//弱引用没有重载->指针运算符,强引用有的boost::shared_ptr<X> p3 = p.lock();if (!p3)cout<<"object is destroyed"<<endl;//p.lock()看下能否提升,lock()表示提升,也表示锁定对象,防止被销毁elsep3->Fun();}//p2引用的对象会被销毁,因为引用计数=1boost::shared_ptr<X> p4 = p.lock();if (!p4)cout<<"object is destroyed"<<endl;elsep4->Fun();boost::scoped_array<X> xx(new X[3]);// boost::scoped_ptr<X> xx(new X[3]);//error,析构不带[]return  0;
}
  • 测试:
    在这里插入图片描述
    析构函数带[]
    在这里插入图片描述
    在这里插入图片描述

6.PIMPL技法

  • 引入更多的头文件,降低编译速度
    y.cpp和main.cpp都引入了x.h
  • 提高模块的耦合度
    编译期:Y类依赖X的实现,X类改变了,Y需要重新编译
    运行期:若X类有子类,子类若有Fun(),则无法实现替换,无法使用多态
  • 降低了接口的稳定程度
    (1)对于库的使用,方法不能改变
    (2)对于库的编译,动态库的变更,客户程序不用重新编译
    若没有下面的动态库和客户程序的区分,那么如果X改变,则会影响Y,就会影响main.cpp,则所有程序都需要重新编译
  • 不使用PIMPL的eg

//假设下面是动态库start
//file y.h
#include "x.h"
class Y
{
public:void Func_Y();X x_;
};//file y.cpp
#include "y.h"
void Y::Fun()
{return x_.Fun_X();
}
//end//假设下面是客户程序
//file main.cpp
#include "y.h"
int main(void)
{Y y;y.Fun();
}
  • PIMPL技法
  • PIMPL(private implementation或pointer to implementation)也称之为handle/body idiom
    将实现隐藏,或者将指针指向一个实现,或者指针称之为handle,指针指向的实现称之为body(指针指向惯用法)
  • PIML背后的思想是把客户与所有关于类的私有部分隔离开。避免其他类知道其内部结构
    具体做法就是用一个指针来解决,因为类X发生了改变,指针大小是不变的,所以Y类是不用编译的,可以降低编译量
  • 降低编译依赖,提高重编译速度
  • 接口和实现分离
  • 降低模块的耦合度
    编译器
    运行期
  • 提高了接口的稳定程度
    (1)对于库的使用,方法不能改变
    (2)对于库的编译,动态库的变更,客户程序不用编译
    假设X发生改变,意味着库要进行变更,但是客户程序不需要编译,因为Y与其内部的实现细节是分离的,只要Y的接口保持不变。
  • PIMPL的eg:P87\12.cpp

//假设下面是动态库start
//y.h不需要包含x.h,只需要前向声明,因为指针的原因X*
//file y.h
class Y
{Y();~Y();void Fun();X* px_;//即使类X发生变化,Y类不需要编译,指针所指向的类到底是怎么实现的,分离了//因为指针总是4个字节或者8个字节//在运行期,还可以应用多态,因为这是指针//也可以用智能指针,因为智能指针所持有的对象类型发生了改变,但智能指针的大小是不会改变的//智能指针还能自动管理px_的生存期
};//file y.cpp
#include "x.h"
Y::Y() : px_(new X) {}
Y::~Y() {delete px_; px_ = 0;}
void Y::Fun() {return px_->Fun();}
//end//假设下面是客户程序
//file main.cpp
#include "y.h"//这里y.h没有包含x.h
int main(void) 
{Y y;y.Fun();
}
  • eg:pimpl的又一个eg
//类Y依赖下面的三个类,相当于要依赖他们具体的实现了
class Y
{A a;B b;C c;
};可以将他们提升到一个类中
class Y
{Impl* p;
};
class Impl
{A a;B b;C c;
};
  • 参考:从零开始学C++之boost库(一):详解 boost 库智能指针(scoped_ptr 、shared_ptr 、weak_ptr 源码分析)

http://www.ppmy.cn/news/289765.html

相关文章

数据库p88-表格代码mysql

#81-例5.4 use stuexpm; insert into studentInfo values (181001,成志强,男,1998-08-17,计算机,北京市海淀区), (181002,孙红梅,女,1997-11-23,计算机,成都市锦江区), (181003,朱丽,女,1998-02-19,计算机,北京市海淀区), (184001,王智勇,男,1997-12-05,电子信息工程,null), (1…

《汇编语言》王爽 P88 实验3

《汇编语言》王爽 P88 实验3 Mac系统配置这些蛮麻烦的&#xff1a; 下载个DOSBOX&#xff0c;再下载debug&#xff0c;在DOSBOX中把debug挂到C盘去吧 比如我想把air下面的debug文件挂成C盘&#xff0c;就括号中这条命令&#xff1a; &#xff08;mount c /Users/air/debug&…

IRIG-B码对时

前言&#xff1a;最近我在学习IRIG-B码对时时一直对这个对时转换存在一些疑问&#xff0c;几乎在网上搜遍了资料也没有一个清晰的解答&#xff0c;最终直接使用一台时钟服务器、一台精准时间测试仪&#xff0c;进行IRIG-B测试&#xff0c;查看编码译码内容才对IRIG-B对时解析有…

p88-高级-消息- RabbitTemplate发送接受消息序列化机制

SmarTTY中首先搭建环境&#xff0c;过程如图所述&#xff0c;每次只需要走这几步&#xff0c;就可以在rabbitmq的客户端访问到&#xff1a; RabbitTemplate发送接受消息&序列化机制 1、pom.xml <?xml version"1.0" encoding"UTF-8"?> <p…

UML类图箭头总结

概念 1.类&#xff08;Class&#xff09;&#xff1a;使用三层矩形框表示 . 第一层显示类的名称&#xff0c;如果是抽象类&#xff0c;则就用斜体显示 . 第二层是字段和属性 . 第三层是类的方法 . 注意 : 前面的符号&#xff0c;‘’表示public&#xff0c;‘-’表示private&am…

九宫格多级OLED(LCD)菜单

目录 函数指针 函数指针的定义方式 使用举例 菜单索引 索引格式 索引列表 按键获取 UI刷新 光标 页面函数 OLED菜单实现的方法有很多&#xff0c;本文介绍的方法也很常见。相对来说比较特殊的地方就是九宫格&#xff0c;但实现起来难度也不是特别大。本文只介绍了该菜…

PEP8

代码布局 缩进 函数参数列表if 语句条件集合 制表符 or 空格行的最大长度二元运算符空行源文件编码Import 导入模块级的魔法名称 字符串引号表达式和语句中的空格 避免使用无关的空格其他建议 注释 块注释行内注释文档字符串 命名规范 命名风格命名约定 应避免的名字包名和模块…

C++核心之程序的内存模型P84-P88

内存分区模型&#xff1a; C程序在执行时&#xff0c;将内存大方向划分为4个区域 代码区&#xff1a;存放函数体的二进制代码&#xff0c;由操作系统进行管理的全局区&#xff1a;存放全局变量和静态变量以及常量栈区&#xff1a;由编译器自动分配释放, 存放函数的参数值,局部…

【统计学习|书籍阅读】第六章 logistics回国和最大熵模型 p77-p88

文章目录 思路logistic回归模型最大熵模型最大熵模型定义最大熵模型的学习极大似然估计 模型学习的最优化算法 思路 logistic 回归是统计学习的经典分类方法。最大熵是概率模型学习的一个准则&#xff0c;将其推广到分类问题得到最大熵模型。 logistic回归模型 logistic分布…

阿里P8熬了一个月肝出这份阿里内部(泰山版),在Github标星31K+

2021年的互联网行业竞争越来越严峻&#xff0c;面试也是越来越难&#xff0c;一直以来我都想整理一套完美的面试宝典&#xff0c;奈何难抽出时间&#xff0c;这套阿里巴巴泰山版的Java面试手册我整理了整整1个月&#xff0c;上传到Git上目前star数达到了30K 然后看到好多同学 …

P88页例题

&#xff08;1&#xff09;向TeacherInfo表插入样本数据 &#xff08;2&#xff09;向Courselnfo表插入样本数据。 &#xff08;3&#xff09;使用INSERT INTOSELECT语句&#xff0c;将TeacherInfo表的记录快速插人TeacherInfol表中。 4&#xff09;采用三种不同的方法&#…

p88 SRC挖掘-拿下CNVD证书开源闭源售卖系统

数据来源 ​ 1&#xff0e;开源系统、闭源系统、售卖系统 通用性100 &#xff1a;表示挖到的漏洞影响影响范围&#xff08;服务器、ip这些&#xff09;个数达到100以上 分类、解释、区别 开源系统&#xff1a;可以拿到源码闭源系统&#xff1a;一般拿不到源码售卖系统&…

人工智能导论期末复习

配套教材人工智能导论第五版王万良著 第一章 绪论 了解人工智能的基本概念 P2 P5智能的特征&#xff08;4个&#xff09; P2~4 感知、记忆思维、学习、行为能力 思维&#xff08;3个&#xff09;---简答 P3 逻辑、形象、顿悟思维 人工智能的知识表示&…

JavaScript第九篇(p88~p102)

文章目录 正则表达式语法邮件的正则&#xff08;p90&#xff09;DOM简介&#xff08;p91&#xff09;什么是 DOM&#xff1f;节点节点的属性获取对象 事件的简介&#xff08;p92&#xff09;文档的加载&#xff08;p93&#xff09;dom查询&#xff08;p94&#xff09;getElemen…

[C++黑马程序员笔记]P84-P88程序的内存模型

视频地址&#xff1a;黑马程序员匠心之作|C教程从0到1入门编程,学习编程不再难_哔哩哔哩_bilibili 目录 P84-P85程序的内存模型-内存四区-代码区、全局区 P86程序的内存模型-内存四区-栈区 P87程序的内存模型-内存四区-堆区 P88程序的内存模型-new运算 总结 C程序在执行时…

数据结构与算法(Python语言描述)P86和P88判断谓词和谓词参数的理解

1.书中说的"判断谓词"和"谓词参数" P86页代码如下&#xff1a; def find(self, pred):p self._headwhile p is not None:if pred(p.elem):return p.elemp p.next这里的 pred 是一个函数&#xff0c;相当于形参里参入一个实现判断功能的函数&#xff0c…

书:计算机网络高级软件编程技术(P88) 之 基础训练:路由追踪程序的实现(tracert程序)

Section I Problem Specification 本次实验主要是写一个程序&#xff1a;能够追踪到达某外网ip时&#xff0c;所经过的路由器。也就说是&#xff1a;当我向某个ip地址发包时&#xff0c;是经过路由器帮我转发这些包&#xff0c;我现在就是想把这些经过的路由的ip显示出来。 ICM…

P88 例4-3 编写一个程序,测试BFIndex()函数的正确性。

P88 例4-3 编写一个程序&#xff0c;测试BFIndex()函数的正确性。 头文件&#xff1a;DString.h #include<stdio.h> #include<stdlib.h> #include<string.h>typedef struct {char* str;int maxLength;int length; }DString;void Initiate(DString* S, int…

MySQL优化五-高性能的8个索引策略

正确创建和使用索引策略是实现高性能查询的基础&#xff0c;本文总结7个索引策略。 一、独立的列 独立的列是指索引不能是表达式的一部分&#xff0c;也不能是函数的参数。 mysql>select id from actor where id1 5; //错误mysql>select id from actor where id …