我的编程空间,编程开发者的网络收藏夹
学习永远不晚

C++中的异常处理机制介绍

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

C++中的异常处理机制介绍

本篇内容介绍了“C++中的异常处理机制介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

异常处理

增强错误恢复能力是提高代码健壮性的最有力的途径之一,C语言中采用的错误处理方法被认为是紧耦合的,函数的使用者必须在非常靠近函数调用的地方编 写错误处理代码,这样会使得其变得笨拙和难以使用。C++中引入了异常处理机制,这是C++的主要特征之一,是考虑问题和处理错误的一种更好的方式。使用 错误处理可以带来一些优点,如下:

  • 错误处理代码的编写不再冗长乏味,并且不再和正常的代码混合在一起,程序员只需要编写希望产生的代码,然后在后面某个单独的区段里编写处理错误的嗲吗。多次调用同一个函数,则只需要某个地方编写一次错误处理代码。

  • 错误不能被忽略,如果一个函数必须向调用者发送一次错误信息。它将抛出一个描述这个错误的对象。

传统的错误处理和异常处理

在讨论异常处理之前,我们先谈谈C语言中的传统错误处理方法,这里列举了如下三种:

  • 在函数中返回错误,函数会设置一个全局的错误状态标志。

  • 使用信号来做信号处理系统,在函数中raise信号,通过signal来设置信号处理函数,这种方式耦合度非常高,而且不同的库产生的信号值可能会发生冲突

  • 使用标准C库中的非局部跳转函数 setjmp和longjmp ,这里使用setjmp和longjmp来演示下如何进行错误处理:

#include <iostream> #include <setjmp.h> jmp_buf static_buf; //用来存放处理器上下文,用于跳转  void do_jmp() {     //do something,simetime occurs a little error     //调用longjmp后,会载入static_buf的处理器信息,然后第二个参数作为返回点的setjmp这个函数的返回值     longjmp(static_buf,10);//10是错误码,根据这个错误码来进行相应的处理 }  int main() {     int ret = 0;     //将处理器信息保存到static_buf中,并返回0,相当于在这里做了一个标记,后面可以跳转过来     if((ret = setjmp(static_buf)) == 0) {         //要执行的代码         do_jmp();     } else {    //出现了错误         if (ret == 10)             std::cout << "a little error" << std::endl;     } }

错误处理方式看起来耦合度不是很高,正常代码和错误处理的代码分离了,处理处理的代码都汇聚在一起了。但是基于这种局部跳转的方式来处理代码,在 C++中却存在很严重的问题,那就是对象不能被析构,局部跳转后不会主动去调用已经实例化对象的析构函数。这将导致内存泄露的问题。下面这个例子充分显示 了这点

#include <iostream> #include <csetjmp>  using namespace std;  class base {     public:         base() {             cout << "base construct func call" << endl;         }         ~base() {             cout << "~base destruct func call" << endl;         } };  jmp_buf static_buf;  void test_base() {     base b;     //do something     longjmp(static_buf,47);//进行了跳转,跳转后会发现b无法析构了 }  int main() {     if(setjmp(static_buf) == 0) {         cout << "deal with some thing" << endl;         test_base();     } else {         cout << "catch a error" << endl;     } }

在上面这段代码中,只有base类的构造函数会被调用,当longjmp发生了跳转后,b这个实例将不会被析构掉,但是执行流已经无法回到这里,b 这个实例将不会被析构。这就是局部跳转用在C++中来处理错误的时候带来的一些问题,在C++中异常则不会有这些问题的存在。那么接下来看看如何定义一个 异常,以及如何抛出一个异常和捕获异常吧.

异常的抛出

class MyError {     const char* const data; public:     MyError(const char* const msg = 0):data(msg)     {         //idle     } };  void do_error() {     throw MyError("something bad happend"); }  int main() {     do_error(); }

上面的例子中,通过throw抛出了一个异常类的实例,这个异常类,可以是任何一个自定义的类,通过实例化传入的参数可以表明发生的错误信息。其实 异常就是一个带有异常信息的类而已。异常被抛出后,需要被捕获,从而可以从错误中进行恢复,那么接下来看看如何去捕获一个异常吧。在上面这个例子中使用抛 出异常的方式来进行错误处理相比与之前使用局部跳转的实现来说,***的不同之处就是异常抛出的代码块中,对象会被析构,称之为堆栈反解.

异常的捕获

C++中通过catch关键字来捕获异常,捕获异常后可以对异常进行处理,这个处理的语句块称为异常处理器。下面是一个简单的捕获异常的例子:

try{     //do something     throw string("this is exception"); } catch(const string& e) {     cout << "catch a exception " << e << endl; }

catch有点像函数,可以有一个参数,throw抛出的异常对象,将会作为参数传递给匹配到到catch,然后进入异常处理器,上面的代码仅仅是 展示了抛出一种异常的情况,加入try语句块中有可能会抛出多种异常的,那么该如何处理呢,这里是可以接多个catch语句块的,这将导致引入另外一个问 题,那就是如何进行匹配。

异常的匹配

异常的匹配我认为是符合函数参数匹配的原则的,但是又有些不同,函数匹配的时候存在类型转换,但是异常则不然,在匹配过程中不会做类型的转换,下面的例子说明了这个事实:

#include <iostream>  using namespace std; int main() {     try{          throw 'a';     }catch(int a) {         cout << "int" << endl;     }catch(char c) {         cout << "char" << endl;     } }

上面的代码的输出结果是char,因为抛出的异常类型就是char,所以就匹配到了第二个异常处理器。可以发现在匹配过程中没有发生类型的转换。将 char转换为int。尽管异常处理器不做类型转换,但是基类可以匹配到派生类这个在函数和异常匹配中都是有效的,但是需要注意catch的形参需要是引 用类型或者是指针类型,否则会 导致切割派生类这个问题。

//基类 class Base{     public:         Base(string msg):m_msg(msg)         {         }         virtual void what(){             cout << m_msg << endl;         }     void test()     {         cout << "I am a CBase" << endl;     }     protected:         string m_msg; }; //派生类,重新实现了虚函数 class CBase : public Base {     public:         CBase(string msg):Base(msg)         {          }         void what()         {            cout << "CBase:" << m_msg << endl;         } };  int main() {     try {         //do some thing     //抛出派生类对象         throw CBase("I am a CBase exception");      }catch(Base& e) {  //使用基类可以接收         e.what();     } }

上面的这段代码可以正常的工作,实际上我们日常编写自己的异常处理函数的时候也是通过继承标准异常来实现字节的自定义异常的,但是如果将 Base&换成Base的话,将会导致对象被切割,例如下面这段代码将会编译出错,因为CBase被切割了,导致CBase中的test函数无法 被调用。

try {     //do some thing     throw CBase("I am a CBase exception");  }catch(Base e) {     e.test(); }

到此为此,异常的匹配算是说清楚了,总结一下,异常匹配的时候基本上遵循下面几条规则:

异常匹配除了必须要是严格的类型匹配外,还支持下面几个类型转换.

  • 允许非常量到常量的类型转换,也就是说可以抛出一个非常量类型,然后使用catch捕捉对应的常量类型版本

  • 允许从派生类到基类的类型转换

  • 允许数组被转换为数组指针,允许函数被转换为函数指针

假想一种情况,当我要实现一代代码的时候,希望无论抛出什么类型的异常我都可以捕捉到,目前来说我们只能写上一大堆的catch语句捕获所有可能在 代码中出现的异常来解决这个问题,很显然这样处理起来太过繁琐,幸好C++提供了一种可以捕捉任何异常的机制,可以使用下列代码中的语法。

catch(...) {
    //异常处理器,这里可以捕捉任何异常,带来的问题就是无法或者异常信息
   }

如果你要实现一个函数库,你捕捉了你的函数库中的一些异常,但是你只是记录日志,并不去处理这些异常,处理异常的事情会交给上层调用的代码来处理.对于这样的一个场景C++也提供了支持.

try{     throw Exception("I am a exception");    }catch(...) {     //log the exception     throw; }

通过在catch语句块中加入一个throw,就可以把当前捕获到的异常重新抛出.在异常抛出的那一节中,我在代码中抛出了一个异常,但是我没有使用任何catch语句来捕获我抛出的这个异常,执行上面的程序会出现下面的结果.

terminate called after throwing an instance of 'MyError' Aborted (core dumped)

为什么会出现这样的结果呢?,当我们抛出一个异常的时候,异常会随着函数调用关系,一级一级向上抛出,直到被捕获才会停止,如果最终没有被捕获将会 导致调用terminate函数,上面的输出就是自动调用terminate函数导致的,为了保证更大的灵活性,C++提供了set_terminate 函数可以用来设置自己的terminate函数.设置完成后,抛出的异常如果没有被捕获就会被自定义的terminate函数进行处理.下面是一个使用的 例子:

#include <exception> #include <iostream> #include <cstdlib> using namespace std;  class MyError {     const char* const data; public:     MyError(const char* const msg = 0):data(msg)     {         //idle     } };  void do_error() {     throw MyError("something bad happend"); } //自定义的terminate函数,函数原型需要一致 void terminator() {     cout << "I'll be back" << endl;     exit(0); }  int main() {     //设置自定义的terminate,返回的是原有的terminate函数指针     void (*old_terminate)() = set_terminate(terminator);     do_error(); } 上面的代码会输出I'll be back

到此为此关于异常匹配的我所知道的知识点都已经介绍完毕了,那么接着可以看看下一个话题,异常中的资源清理.

异常中的资源清理

在谈到局部跳转的时候,说到局部调转不会调用对象的析构函数,会导致内存泄露的问题,C++中的异常则不会有这个问题,C++中通过堆栈反解将已经 定义的对象进行析构,但是有一个例外就是构造函数中如果出现了异常,那么这会导致已经分配的资源无法回收,下面是一个构造函数抛出异常的例子:

#include <iostream> #include <string> using namespace std;  class base {     public:         base()         {             cout << "I start to construct" << endl;             if (count == 3) //构造第四个的时候抛出异常                 throw string("I am a error");             count++;         }          ~base()         {             cout << "I will destruct " << endl;         }     private:         static int count; };  int base::count = 0;  int main() {         try{              base test[5];          } catch(...){              cout << "catch some error" << endl;          } } 上面的代码输出结果是: I start to construct I start to construct I start to construct I start to construct I will destruct I will destruct I will destruct catch some error

在上面的代码中构造函数发生了异常,导致对应的析构函数没有执行,因此实际编程过程中应该避免在构造函数中抛出异常,如果没有办法避免,那么一定要 在构造函数中对其进行捕获进行处理.***介绍一个知识点就是函数try语句块,如果main函数可能会抛出异常该怎么捕获?,如果构造函数中的初始化列表 可能会抛出异常该怎么捕获?下面的两个例子说明了函数try语句块的用法:

#include <iostream>  using namespace std;  int main() try {     throw "main"; } catch(const char* msg) {     cout << msg << endl;     return 1; } main函数语句块,可以捕获main函数中抛出的异常. class Base {     public:         Base(int data,string str)try:m_int(data),m_string(str)//对初始化列表中可能会出现的异常也会进行捕捉        {             // some initialize opt        }catch(const char* msg) {              cout << "catch a exception" << msg << endl;        }      private:         int m_int;         string m_string; };  int main() {     Base base(1,"zhangyifei"); }

上面说了很多都是关于异常的使用,如何定义自己的异常,编写异常是否应该遵循一定的标准,在哪里使用异常,异常是否安全等等一系列的问题,下面会一一讨论的.

标准异常

C++标准库给我们提供了一系列的标准异常,这些标准异常都是从exception类派生而来,主要分为两大派生类,一类是 logic_error,另一类则是runtime_error这两个类在stdexcept头文件中,前者主要是描述程序中出现的逻辑错误,例如传递了 无效的参数,后者指的是那些无法预料的事件所造成的错误,例如硬件故障或内存耗尽等,这两者都提供了一个参数类型为std::string的构造函数,这 样就可以将异常信息保存起来,然后通过what成员函数得到异常信息.

#include <stdexcept> #include <iostream> #include <string> using namespace std;  class MyError:public runtime_error { public:     MyError(const string& msg = "") : runtime_error(msg) {}  };  //runtime_error logic_error 两个都是继承自标准异常,带有string构造函数 // int main() {     try {         throw MyError("my message");       }   catch(MyError& x) {         cout << x.what() << endl;        } }

异常规格说明

假设一个项目中使用了一些第三方的库,那么第三方库中的一些函数可能会抛出异常,但是我们不清楚,那么C++提供了一个语法,将一个函数可能会抛出 的异常列出来,这样我们在编写代码的时候参考函数的异常说明即可,但是C++11中这中异常规格说明的方案已经被取消了,所以我不打算过多介绍,通过一个 例子看看其基本用法即可,重点看看C++11中提供的异常说明方案:

#include <exception> #include <iostream> #include <cstdio> #include <cstdlib> using namespace std;  class Up{}; class Fit{}; void g(); //异常规格说明,f函数只能抛出Up 和Fit类型的异常 void f(int i)throw(Up,Fit) {     switch(i) {         case 1: throw Up();         case 2: throw Fit();        }     g(); }  void g() {throw 47;}  void my_ternminate() {     cout << "I am a ternminate" << endl;     exit(0); }  void my_unexpected() {     cout << "unexpected exception thrown" << endl; //   throw Up();     throw 8;     //如果在unexpected中继续抛出异常,抛出的是规格说明中的 则会被捕捉程序继续执行     //如果抛出的异常不在异常规格说明中分两种情况     //1.异常规格说明中有bad_exception ,那么会导致抛出一个bad_exception     //2.异常规格说明中没有bad_exception 那么会导致程序调用ternminate函数    // exit(0); }  int main() { set_terminate(my_ternminate); set_unexpected(my_unexpected); for(int i = 1;i <=3;i++) {      //当抛出的异常,并不是异常规格说明中的异常时      //会导致最终调用系统的unexpected函数,通过set_unexpected可以      //用来设置自己的unexpected汗函数     try {         f(i);        }catch(Up) {         cout << "Up caught" << endl;        }catch(Fit) {         cout << "Fit caught" << endl;        }catch(bad_exception) {         cout << "bad exception" << endl;        } } }

上面的代码说明了异常规格说明的基本语法,以及unexpected函数的作用,以及如何自定义自己的unexpected函数,还讨论了在 unexpected函数中继续抛出异常的情况下,该如何处理抛出的异常.C++11中取消了这种异常规格说明.引入了一个noexcept函数,用于表 明这个函数是否会抛出异常

void recoup(int) noexecpt(true);  //recoup不会抛出异常
void recoup(int) noexecpt(false); //recoup可能会抛出异常

此外还提供了noexecpt用来检测一个函数是否不抛出异常.

异常安全

异常安全我觉得是一个挺复杂的点,不光光需要实现函数的功能,还要保存函数不会在抛出异常的情况下,出现不一致的状态.这里举一个例子,大家在实现 堆栈的时候经常看到书中的例子都是定义了一个top函数用来获得栈顶元素,还有一个返回值是void的pop函数仅仅只是把栈顶元素弹出,那么为什么没有 一个pop函数可以 即弹出栈顶元素,并且还可以获得栈顶元素呢?

template<typename T> T stack<T>::pop() {     if(count == 0)         throw logic_error("stack underflow");     else         return data[--count]; }

如果函数在***一行抛出了一个异常,那么这导致了函数没有将退栈的元素返回,但是Count已经减1了,所以函数希望得到的栈顶元素丢失了.本质原 因是因为这个函数试图一次做两件事,1.返回值,2.改变堆栈的状态.***将这两个独立的动作放到两个独立的函数中,遵守内聚设计的原则,每一个函数只做 一件事.我们 再来讨论另外一个异常安全的问题,就是很常见的赋值操作符的写法,如何保证赋值操作是异常安全的.

class Bitmap {...}; class Widget {     ... private:     Bitmap *pb;  }; Widget& Widget::operator=(const Widget& rhs) {     delete pb;     pb = new Bitmap(*rhs.pb);     return *this; }

上面的代码不具备自我赋值安全性,倘若rhs就是对象本身,那么将会导致*rhs.pb指向一个被删除了的对象.那么就绪改进下.加入证同性测试.

Widget& Widget::operator=(const Widget& rhs) {     If(this == rhs) return *this; //证同性测试     delete pb;     pb = new Bitmap(*rhs.pb);     return *this; }

但是现在上面的代码依旧不符合异常安全性,因为如果delete pb执行完成后在执行new Bitmap的时候出现了异常,则会导致最终指向一块被删除的内存.现在只要稍微改变一下,就可以让上面的代码具备异常安全性.

Widget& Widget::operator=(const Widget& rhs) {     If(this == rhs) return *this; //证同性测试     Bitmap *pOrig = pb;     pb = new Bitmap(*rhs.pb); //现在这里即使发生了异常,也不会影响this指向的对象     delete pOrig;     return *this;   }

这个例子看起来还是比较简单的,但是用处还是很大的,对于赋值操作符来说,很多情况都是需要重载的.

“C++中的异常处理机制介绍”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注编程网网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

C++中的异常处理机制介绍

下载Word文档到电脑,方便收藏和打印~

下载Word文档

猜你喜欢

C++中的异常处理机制介绍

本篇内容介绍了“C++中的异常处理机制介绍”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!异常处理增强错误恢复能力是提高代码健壮性的最有力的途
2023-06-17

Java中的异常处理机制介绍(非常全面!)

异常可能是在程序执行过程中产生的,也可能是程序中throw主动抛出的,下面这篇文章主要给大家介绍了关于Java中异常处理机制的相关资料,文中通过实例代码介绍的非常详细,需要的朋友可以参考下
2023-01-18

C++ 异常处理 catch(...)介绍

catch(…)能够捕获多种数据类型的异常对象,所以它提供给程序员一种对异常 对象更好的控制手段,使开发的软件系统有很好的可靠性
2022-11-15

Java异常机制的详细介绍

本篇内容主要讲解“Java异常机制的详细介绍”,感兴趣的朋友不妨来看看。本文介绍的方法操作简单快捷,实用性强。下面就让小编来带大家学习“Java异常机制的详细介绍”吧!1.异常的概述1.1什么是异常?异常:程序在运行过程中发生由于外部问题导
2023-06-02

java中异常类型及异常处理的详细介绍

一、异常实现及分类1.先看下异常类的结构图上图可以简单展示一下异常类实现结构图,当然上图不是所有的异常,用户自己也可以自定义异常实现。上图已经足够帮我们解释和理解异常实现了:java相关免费视频教程:java教学视频1.所有的异常都是从Throwable继承而
java中异常类型及异常处理的详细介绍
2015-02-22

如何实现C++中的异常处理机制?

如何实现C++中的异常处理机制?引言:异常处理是编程中非常重要的一部分,它可以提高程序的可靠性和稳定性。在C++中,异常处理机制可以帮助我们处理程序中的错误和异常情况,使得程序的控制流能够在异常发生时进行变更,从而避免程序的崩溃。本文将介绍
如何实现C++中的异常处理机制?
2023-11-02

实例介绍java中异常的处理方式

首先处理异常主要有两种方式:一种try catch,一种是throws。一、try catchtry{} 中放入可能发生异常的代码。catch{}中放入对捕获到异常之后的处理。其中catch中e.printStackTrace()作用就是,在控制台打印程序出错
实例介绍java中异常的处理方式
2016-10-03

js中的异常处理try...catch使用介绍

在JavaScript可以使用try...catch来进行异常处理,下面有个不错的示例,大家可以参考下,希望对大家有所帮助
2022-11-15

C++ 技术中的异常处理:不同类型的异常处理机制有哪些?

c++++中异常处理机制有:1. try-catch 块:捕获和处理异常;2. noexcept 规范符:指定函数是否可能抛出异常;3. 运算符重载:重载运算符抛出异常。实战中,try-catch块可处理文件操作中的异常,如文件打开失败和内
C++ 技术中的异常处理:不同类型的异常处理机制有哪些?
2024-05-10

C++嵌入式开发中的异常处理机制

c++++异常处理机制在嵌入式开发中至关重要,可处理超出预期的异常,确保系统稳定性。有两种异常类型:标准异常和用户定义异常,可使用throw抛出异常,使用try-catch捕获异常。实战案例展示异常处理在嵌入式应用程序中的应用,处理eepr
C++嵌入式开发中的异常处理机制
2024-05-11

详解C++中的异常和错误处理机制

在C++编程中,异常处理和错误处理机制是非常重要的,它们可以帮助程序员有效地处理运行时错误和异常情况,本文就来介绍一下C++中的异常处理和错误处理机制吧
2023-05-19

c++异常处理机制是怎么样的

这篇文章主要介绍了c++异常处理机制是怎么样的,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。当一个程序出现错误时,它可能的情况有3种:语法错误,运行时错误和逻辑错误。语法错误
2023-06-17

Java的异常处理机制

本篇内容介绍了“Java的异常处理机制”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!Java 异常处理异常是程序中的一些错误,但并不是所有的
2023-06-02

C++ 函数返回值的异常处理机制

c++++ 函数的返回值在发生异常时未定义,需要通过 try-catch 块捕获异常并采取适当措施:仅在函数无法从错误中恢复时抛出异常。使用明确且有意义的异常类型。在函数文档中记录可能抛出的异常。使用 try-catch 块捕获异常并执行必
C++ 函数返回值的异常处理机制
2024-04-13

loongarch架构介绍(四)TLB异常处理

本文介绍了loongarch架构中软件管理TLB的机制、TLB重填异常和其他TLB相关的异常,以及相应的异常处理和代码分析。
loongarch架构2024-11-30

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录