[学习][记录] c++语言:从放弃到入门 <一> c++11新关键字以及引入的新特性(下)

简介: [学习][记录] c++语言:从放弃到入门 <一> c++11新关键字以及引入的新特性(下)

二十一、 std::bind

21.1 含义

bind 用来将可调用对象和参数一起进行绑定。可调用对象包括普通函数、全局函

数、静态函数、类静态函数甚至是类成员函数,参数包括普通参数和类成员。

语义

std::bind(funcName,argType,…);//绑定以存在的函数名,以及传入的实参

placeholders::_x 实参占位

placeholders::_1 表示第一个实参暂时不填实参数值,依次可推。

21.2 作用

21.2.1 绑定普通函数与参数及占位

double myDivide (double x, double y);
auto fn_five = std::bind (myDivide, 10, 2); 
cout << fn_five() << endl;

21.2.2 绑定对象与成员及占位

class MyPair2 
{
public: 
  int add(int x, int y) 
  { 
return x + y; 
  } 
};
auto bindObjfunc = bind(&MyPair2::add,mp2 , 2, 3); 

21.2.3 函数重载情形

int add(int x, int y);
double add(double x, double y);
auto bindGlobalFunc = 
bind((int(*)(int,int))add,_1,_2);
auto bindGlobalFunc2 = 
bind(static_cast<double(*)(double,double)>(add),_1,_2);

注意

1.预先绑定的参数值通过 值传递进去;通过placehodler传递进去的 传递引用进去

2.bind 返回的是可调用的函数

3.绑定的参数 调用之前 需要确认是可用的

21.3 多态之 bind +fucntion

21.3.1.可实现多态使用

std::function<void(void)> f;
void foo();
void func(int a)
f = std::bind(foo); 
f(); 
f= std::bind(func,1); 
f(); 

21.3.2.function 本是不可以包装类成员函数,bind实现类成员函数的绑定, 然后赋给 fucntion 对象,亦即实现了间接性的包装

std::function<void(void)> f;
class Foo 
{
public: 
void method() 
{ 
cout<<"Foo::void method()"<<endl; 
}
void method2(string s) 
{ 
cout<<"Foo:void method2()"<<endl; 
} 
};
Foo foo; 
f = std::bind(&Foo::method,&foo); 
f(); 
f = std::bind(&Foo::method2,&foo,"china"); 
f();

二十二、 Unordered Contrainer 无序容器

22.1 unordered_map

采用hash_map 数据结构,无序

二十三、 Auto Memeory Manage 自动内存管理

23.1 RAII(Resource Acquisition Is Initialization)

RAII(Resource Acquisition Is Initialization)是一种利用对象生命周期来控制

程序资源(如内存、文件句柄、网络连接、互斥量等等)的简单技术。 RAII 的一般做法是这样的:在对象构造时获取资源,接着控制对资源的访问使之

在对象的生命周期内始终保持有效,最后在对象析构的时候释放资源。借此,我们实际 上把管理一份资源的责任托管给了一个对象。这种做法有两大好处:

①不需要显式地释放资源。 ②采用这种方式,对象所需的资源在其生命期内始终保持有效。

此时,所托管的资源,随对象的创建而获取,随对象的消失而消失,即所谓的 RAII 思想:资源获取即初始化。

原理上,是代理了被托管的对象指针,管理对象的生命周期,即实现自动释放。其 行为类似于所托管的对象指针,原因是,重载了 operator->和 operator*。 如下是智能指针的模板(template)化实现。

template <class T> class SmartPtr {
public:
  explicit SmartPtr(T* pointee) : pointee_(pointee){}
   ~SmartPtr() {
    delete pointee_;
   }
  T& operator*() const { //... 
  return *pointee_;
  }
  T* operator->() const { //... 
  return pointee_; 
  } 
private:
   T* pointee_; //... 
};

23.2 auto_ptr(deprecated)

代理new出来的对象,自动化释放对象,作用域处结束,释放对象。

存在问题

  • 两个auto_ptr对象拥有同一个对象时,析构时都试图删除p,会出现崩溃问题
#include <iostream> 
 #include <memory> 
 using namespace std; 
 int main() {
  int *p = new int(10); 
  {
   auto_ptr<int> ap(p);
   cout<<*ap<<endl;
  }
  auto_ptr<int> ap2(p);
  cout<<*ap2<<endl;
 return 0; 
}
  • 作参数传递的时,亦是会出现同样的情况,两个指针,对同一段资源产生了引用行为。

23.3 unique_ptr

uniqu_ptr 的使用方法,基本上等同于 auto_ptr, 不同之处,就在于实现了资源的 唯一, 既不可以拷贝也不可以赋值,正如其名字一样。

  • 解决了作为 参数拷贝时,无法拷贝和赋值的特性使 只能使用同一个对象,解决auto_ptr造成的释放崩溃
  • 判断是否有资源
unique_ptr<Copy> up; 
if(!up)
{
  cout<<"无资源托管"<<endl; 
}
unique_ptr<Copy> up2(new Copy(10)); 
if(up2)
{
 cout<<"有资源托管"<<endl;
 }
  • 允许托管左值 unique_ptr up2 =std::move(up); 相当于资源转移,被转移的资源不允许再使用
int main() { 
  unique_ptr<Copy> up(new Copy(99));
  cout<<up.get()<<endl;
  unique_ptr<Copy> up2 =std::move(up);
  cout<<up2.get()<<endl;
  //up.get();//被转移资源 再使用 会造成崩溃 
}

23.3.1 常用函数

  • get() 返回所托管资源的指针
  • release() 取消代理(放弃托管) ,返回资源句柄,注意:对象释放仍需手动维护
  • reset() 重置 1.参数为空 释放之前的资源对象 2.参数为对象指针,先释放之前的资源对象,重新托管新的对象
  • std::move() 允许托管左值 相当于资源转移,被转移的资源不允许再使用

23.4 shared_ptr

shared_ptr之间共享资源,共享同一个计数器,每次引用,引用计数+1

int main() { 
  shared_ptr<int> sp(new int(10)); 
  cout<<sp.get()<<endl;
  if(sp) {
  cout<<"有资源托管中"<<endl;
  } 
  cout<<sp.use_count()<<endl;
   {
    shared_ptr<int> sp2 = sp; 
    cout<<sp2.use_count()<<endl; 
  }
  cout<<sp.use_count()<<endl;
  return 0; 
}
输出结果:
有资源托管中

比较:

  • uinque_ptr 解决了 auto_ptr 中引用同一个对象的问题,方式就是不可引用同一个 对象。
  • shared_ptr 解决了 auto_ptr 中引用同一个对象,共同拥有一个资源, 但不会重 析构的问题,原理是,在内部保持一个引用计数,并且仅当引用计数为 0 才能被删除, 不可以用数组。

都无法避免作用域重复析构崩溃

23.5 用法

  • 基本类型计数测试
#include <iostream>
 #include <memory> 
 using namespace std; 
 void func(shared_ptr<int> sp) {
 // sp.reset(); //此处仅将自己所累积的计数减 1 
 cout<<sp.use_count()<<endl; sp.reset(); //此时 reset 等价于 sp 对象消失,若己为零,则不再减 1. 
 }
int main() { 
shared_ptr<int> sp(new int(10)); 
cout<<sp.get()<<endl;
if(sp){
  cout<<"有资源托管中"<<endl;
}
cout<<sp.use_count()<<endl; 
shared_ptr<int> sp2 = sp; 
cout<<sp2.use_count()<<endl; 
cout<<sp.use_count()<<endl; 
func(sp);
cout<<sp.use_count()<<endl; 
return 0; 
}
  • 对象计数测试

reset 跟参数,会托管新对象,释放旧对象,如若不跟参数话,会将当前对象的引 用计数减 1

#include <iostream> 
#include <memory> 
using namespace std; 
class A {
public: A() { 
  cout<<"A()"<<this<<endl; }
~A() { 
  cout<<"~A()"<<this<<endl; 
}
void dis() { 
  cout<<"A::void dis()"<<endl; 
} 
};
int main1() { 
{ 
 shared_ptr<A> sp(new A);
 sp.reset(new A()); 
 cout<<"+++++++++++++++++++++"<<endl; 
}
cout<<"======================"<<endl;
}
int main() 
{ 
  { 
    shared_ptr<A> sp(new A); 
    sp.reset();sp.reset();sp.reset(); 
    cout<<"+++++++++++++++++++++"<<endl; 
  }
  cout<<"======================"<<endl; 
}
  • 对象传参测试
#include <iostream> 
#include <memory> 
using namespace std; 
class A {public: A() {
 cout<<"A()"<<this<<endl; 
}
~A() { 
cout<<"~A()"<<this<<endl; 
}
void dis() { 
 cout<<"A::void dis()"<<endl; 
} 
};
void func(shared_ptr<A> &sp) //shared_ptr<A> &sp 
{ 
  cout<<sp.use_count()<<endl; 
  sp.reset(); sp.reset(); 
  cout<<"======================"<<endl; 
}
int main() 
{ 
  shared_ptr<A> sp(new A);
  cout<<sp.use_count()<<endl; 
  func(sp); 
  cout<<sp.use_count()<<endl; 
  shared_ptr<A> sp2 = std::move(sp); //移动会将计数也一起移走 
  cout<<sp2.use_count()<<endl; 
  cout<<sp.use_count()<<endl; //此时资源为 0 
  return 0; 
}

对同一个对象,多次 reset 的结果,是仅对自己增加的计数减 1。要保证,当前的 对象的使用安全性。也不会对其它象的使用造成影响。

void func(shared_ptr<Copy> spc) //&spc 若传递的是引用,则引用计数不会加 1。离开函数也不会减 1 
shared_ptr<A> sp2 = std::move(sp); //移动会将计数也一起移走

23.5.1 常用函数

  • reset() 只可自杀 不可他杀
  • std::move() 计数不会增加
  • operator bool 判空
  • operator= 支持赋值,复制

23.6 weak_ptr

#include <memory>
std::weak_ptr<int> wp1;

只能和 shared_ptr 类型指针搭配使用。甚至于,我们可以将 weak_ptr 类型指针视为 shared_ptr 指针的一种辅助工具。

借助 weak_ptr 类型指针, 我们可以获取 shared_ptr 指针的一些状态信息:

  • 有多少指向相同的 shared_ptr 指针、
  • shared_ptr 指针指向的堆内存是否已经被释放等等。

注意:

当 weak_ptr 类型指针的指向和某一 shared_ptr 指针相同时,weak_ptr 指针并不会使所指堆内存的引用计数加 1;

同样,当 weak_ptr 指针被释放时,之前所指堆内存的引用计数也不会因此而减 1。

也就是说,weak_ptr 类型指针并不会影响所指堆内存空间的引用计数。

相关文章
|
17天前
|
存储 负载均衡 算法
基于 C++ 语言的迪杰斯特拉算法在局域网计算机管理中的应用剖析
在局域网计算机管理中,迪杰斯特拉算法用于优化网络路径、分配资源和定位故障节点,确保高效稳定的网络环境。该算法通过计算最短路径,提升数据传输速率与稳定性,实现负载均衡并快速排除故障。C++代码示例展示了其在网络模拟中的应用,为企业信息化建设提供有力支持。
43 15
|
6天前
|
存储 分布式计算 编译器
C++入门基础2
本内容主要讲解C++中的引用、inline函数和nullptr。引用是变量的别名,与原变量共享内存,定义时需初始化且不可更改指向对象,适用于传参和返回值以提高效率;const引用可增强代码灵活性。Inline函数通过展开提高效率,但是否展开由编译器决定,不建议分离声明与定义。Nullptr用于指针赋空,取代C语言中的NULL。最后鼓励持续学习,精进技能,提升竞争力。
|
1月前
|
存储 缓存 C++
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
C++ 标准模板库(STL)提供了一组功能强大的容器类,用于存储和操作数据集合。不同的容器具有独特的特性和应用场景,因此选择合适的容器对于程序的性能和代码的可读性至关重要。对于刚接触 C++ 的开发者来说,了解这些容器的基础知识以及它们的特点是迈向高效编程的重要一步。本文将详细介绍 C++ 常用的容器,包括序列容器(`std::vector`、`std::array`、`std::list`、`std::deque`)、关联容器(`std::set`、`std::map`)和无序容器(`std::unordered_set`、`std::unordered_map`),全面解析它们的特点、用法
C++ 容器全面剖析:掌握 STL 的奥秘,从入门到高效编程
|
4月前
|
安全 编译器 C++
【C++11】新特性
`C++11`是2011年发布的`C++`重要版本,引入了约140个新特性和600个缺陷修复。其中,列表初始化(List Initialization)提供了一种更统一、更灵活和更安全的初始化方式,支持内置类型和满足特定条件的自定义类型。此外,`C++11`还引入了`auto`关键字用于自动类型推导,简化了复杂类型的声明,提高了代码的可读性和可维护性。`decltype`则用于根据表达式推导类型,增强了编译时类型检查的能力,特别适用于模板和泛型编程。
39 2
|
5月前
|
C++
C++ 20新特性之结构化绑定
在C++ 20出现之前,当我们需要访问一个结构体或类的多个成员时,通常使用.或->操作符。对于复杂的数据结构,这种访问方式往往会显得冗长,也难以理解。C++ 20中引入的结构化绑定允许我们直接从一个聚合类型(比如:tuple、struct、class等)中提取出多个成员,并为它们分别命名。这一特性大大简化了对复杂数据结构的访问方式,使代码更加清晰、易读。
78 0
|
1月前
|
编译器 C++ 开发者
【C++篇】深度解析类与对象(下)
在上一篇博客中,我们学习了C++的基础类与对象概念,包括类的定义、对象的使用和构造函数的作用。在这一篇,我们将深入探讨C++类的一些重要特性,如构造函数的高级用法、类型转换、static成员、友元、内部类、匿名对象,以及对象拷贝优化等。这些内容可以帮助你更好地理解和应用面向对象编程的核心理念,提升代码的健壮性、灵活性和可维护性。
|
13天前
|
设计模式 安全 C++
【C++进阶】特殊类设计 && 单例模式
通过对特殊类设计和单例模式的深入探讨,我们可以更好地设计和实现复杂的C++程序。特殊类设计提高了代码的安全性和可维护性,而单例模式则确保类的唯一实例性和全局访问性。理解并掌握这些高级设计技巧,对于提升C++编程水平至关重要。
39 16
|
6天前
|
编译器 C++
类和对象(中 )C++
本文详细讲解了C++中的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载和取地址运算符重载等内容。重点分析了各函数的特点、使用场景及相互关系,如构造函数的主要任务是初始化对象,而非创建空间;析构函数用于清理资源;拷贝构造与赋值运算符的区别在于前者用于创建新对象,后者用于已存在的对象赋值。同时,文章还探讨了运算符重载的规则及其应用场景,并通过实例加深理解。最后强调,若类中存在资源管理,需显式定义拷贝构造和赋值运算符以避免浅拷贝问题。
|
6天前
|
存储 编译器 C++
类和对象(上)(C++)
本篇内容主要讲解了C++中类的相关知识,包括类的定义、实例化及this指针的作用。详细说明了类的定义格式、成员函数默认为inline、访问限定符(public、protected、private)的使用规则,以及class与struct的区别。同时分析了类实例化的概念,对象大小的计算规则和内存对齐原则。最后介绍了this指针的工作机制,解释了成员函数如何通过隐含的this指针区分不同对象的数据。这些知识点帮助我们更好地理解C++中类的封装性和对象的实现原理。

热门文章

最新文章