CPP中的异常处理机制,抛出异常时几种方法性能的比较,以及异常处理和继承配合调用多态的一个小项目(顺便贴一个关于win上clion占用内存过高的解决方法)

目录

写在前面

为什么需要异常处理机制?

异常处理机制的方法

异常接口的声明

异常类型的生命周期以及不同类型异常的测试案例

异常处理与继承

异常处理的基本思想

致谢


写在前面

  • 拖更了几天,但是其实博主一直都在学习的,只是没有之前学习时间那么长,在解决完博主的汇报之后马上会重新投入cpp的学习中,这一周准备把cpp基础学完整理完然后下周正式开始数据结构的学习,争取日更,望大家共同监督共同进步,共勉之。

  • 今天写的内容是三天前学习的内容,关于cpp中的异常处理机制,包含了基本处理,一些已经废弃的写法,异常类型的生命周期,异常抛出的性能优化以及一个简单的项目实现。异常处理还是很重要的,即使是短时间内看了第二遍还是收获了很多新的东西。

  • 最近弄了一台新的笔记本,还没有改成linux,听说笔记本改linux很多坑,之前帮同学装过一台r9000p,运行还可以,之后我有空在来跳一跳这个坑,先用这个win弄一弄,还有就是在Windows上面写代码时发现的clion内存占用过多的问题,我直接贴一个回答吧,就不自己写了:缓解CLion因内存不足卡顿的问题 - 简书


为什么需要异常处理机制?

  • 函数是一种以栈结构展开的系统,函数的上下衔接通过返回值逐层传递且不可以跳跃。

  • 异常是另外一种程序控制的机制,可以在出现意外时中断当前的函数,并以某种机制将当前的异常信息回馈给隔代的调用者。

  • 在c语言中,人们常用返回值来实现异常的反馈。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <iostream>
​
#define BUFFSIZE 1024
​
int copyfile(char* dest, char*src){FILE *fp1 = NULL;FILE *fp2 = NULL;
​//rb: open a binary file using read-only authorityfopen_s(&fp1, dest, "rb");if(fp1 == NULL){//if failed in open file return -1return -1;}
​//wb: open a binary file using write-only authorityfopen_s(&fp2, src, "wb");if(fp2==NULL){//if failed in open file return -2return -2;}
​char buffer[BUFFSIZE];int readlen, writelen;//fread() returns the length of reading contentswhile((readlen = fread(buffer, 1, BUFFSIZE, fp1)) > 0){writelen = fwrite(buffer, 1, readlen, fp2);if(writelen!=readlen){//if the reading contents is not same length as that of writing, return -3return -3;}}fclose(fp1);fclose(fp2);//if successful, return 0return 0;
}
​
int main() {int ret = 0;ret = copyfile("dest.txt", "src.txt");if(ret!=0){switch (ret) {case -1:std::cout << "failed in open source file!" << std::endl;break;case -2:std::cout << "failed in open the target file" << std::endl;break;case -3:std::cout << "failed in copy contents" << std::endl;break;default:std::cout << "unknown error" << std::endl;break;}}return 0;
}

异常处理机制的方法:

  • 使用关键字throw在处理异常的程序进行判断和抛出异常。

  • 可以通过不同的数据类型来判断不同的异常类型(支持自定义类型如类和结构体类型),且数据类型不支持隐式类型转换。

  • 关键字trycatch在调用目标函数时将错误抛出,其中try语句包含的内容叫做保护段将可能出现异常的代码置于此处。

  • 在保护段中抛出异常的代码后面的部分将不会被执行,即抛出异常后,异常处理将会立即中断保护段中的代码,并运行catch中的语句(如果被成功捕捉)。

  • 如果异常被正常接收则之后的程序也会正常地运行,如果异常没有被接收,就会进入默认处理方式调用abort(),此时程序会终止。

  • 为了防止程序被终止一般会使用通配符...

  • 如果遇到当前无法处理的异常,可以将其再次抛出,交由下面一层异常处理函数对其处理,一般此操作在catch的最后一个分支中进行。

  • 一个简单的例子(有两种方式类型分别被测试即(int类型和string*类型)注意抛出一个堆内存开辟的异常在异常处理时要记得回收内存,示例代码如下:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <string>
​
#define BUFFSIZE 1024
​
int copyfile(char* dest, char*src){FILE *fp1 = NULL;FILE *fp2 = NULL;
​//rb: open a binary file using read-only authorityfopen_s(&fp1, dest, "rb");if(fp1 == NULL){//if failed in open file return -1//throw -1;throw new std::string("there is no target file!");}
​//wb: open a binary file using write-only authorityfopen_s(&fp2, src, "wb");if(fp2==NULL){//if failed in open file return -2throw -2;}
​char buffer[BUFFSIZE];int readlen, writelen;//fread() returns the length of reading contentswhile((readlen = fread(buffer, 1, BUFFSIZE, fp1)) > 0){writelen = fwrite(buffer, 1, readlen, fp2);if(writelen!=readlen){//if the reading contents is not same length as that of writing, return -3throw -3;}}fclose(fp1);fclose(fp2);//if successful, return 0return 0;
}
​
int main() {int ret = 0;try{ret = copyfile("dest.txt", "src.txt");}catch(int e){std::cout << "there is an error " << e << std::endl;}catch(const std::string *e){std::cout << "there is an error " << *e << std::endl;delete e;}catch(float e){std::cout << "there is an error " << *e << std::endl;}catch(...){std::cout << "unknown error " << std::endl;//if facing the error that cannot be processed in current location, keep throwing the catched will be okay, and it will be caught and processed in next catch operation //throw;}std::cout << "program safely running" << std::endl;
​return 0;
}
​
  • 第一个测试结果(int类型抛出)如下

D:\ClionProject\exception\cmake-build-debug\exception.exe
there is an error -1
program safely running
​
Process finished with exit code 0
  • 第一个测试结果(int类型抛出)如下

D:\ClionProject\exception\cmake-build-debug\exception.exe
there is an error there is no target file!
program safely running
​
Process finished with exit code 0

异常接口的声明

  • 首先这个异常接口现在是出于一种废弃的状态,从c++17之后就不再支持这种书写方法了。

  • 如果一个函数禁止抛出任何异常,则可以使用throw()关键字来声明(这是唯一。一个还可以用的方法,但是目前一般使用noexception)。

异常类型的生命周期以及不同类型异常的测试案例

  • 异常类型会直接跳过栈的限制直接返回至第一个捕捉到他的catch语句中。

  • 在异常之前的局部变量在异常抛出时会正常的被销毁,只有被抛出的类型生命周期有所不同。

    • 抛出普通数据类型类似于返回值,但是由超出了返回值的概念,给一个简单的例子看看吧

    • #include <iostream>
      ​
      void func_test(){throw(1);
      };
      ​
      void throw_test(){func_test();
      }
      ​
      int main() {
      ​try{throw_test();}catch (int e){switch(e){case 1:std::cout << "succeed in catching the basic exception: " << e << std::endl;break;}}return 0;
      }

    • 其输出结果如下,可以看出异常的抛出可以将一个临时变量直接抛出他的作用域,而且可以跨出几个函数的作用域,这这里从func_test >> throw_test >> main:

    • D:\ClionProject\exception\cmake-build-debug\exception.exe
      succeed in catching the basic exception: 1
      ​
      Process finished with exit code 0

  • 第二种类型,字符串,直接返回一个字符串不可以被string 类型的catch捕捉到,如果抛出一段字符串实际上抛出的是一个常字符串的首地址,因此需要用const char*形式的catch接收,而不是string。

  • 具体看一个例子,其中包含了集中关于字符串类型的测试, 为了方便起见定义了一个函数指针,方便对各个测试代码进行调用。

  • 注意我在这里delete掉string*是因为我知道我在这里开辟了一段堆的空间。代码 如下:

    • void test_4_string_throw(){throw "there is an error type string";
      }
      ​
      void test_4_char_throw(){char* ret = "there is an error type string";throw ret;
      }
      ​
      void test_4_string_pointer_throw(){throw new std::string("there is an error type string");
      }
      ​
      typedef void (*functype)();
      ​
      void test_4_string_catch(functype fun){try{fun();}catch (std::string& e){std::cout << "succeed in catching the string exception: " << e << std::endl;}catch (std::string* e){std::cout << "succeed in catching the string pointer exception: " << *e << std::endl;delete e;}catch (char *e){std::cout << "succeed in catching the char* exception: " << e << std::endl;}catch (const char *e){std::cout << "succeed in catching the const char* exception: " << e << std::endl;}
      }
      ​
      int main() {test_4_string_catch(test_4_string_throw);test_4_string_catch(test_4_char_throw);test_4_string_catch(test_4_string_pointer_throw);
      ​return 0;
      }

    • 其运行结果如下,可以看出,字符串被const char*捕捉,char* 和string*类型被各自类型捕捉了,z再次可以看出什么叫做严格捕捉,即使是const 以及char*和 string 类型这种我们常见的隐式类型转换也是绝对不允许的:

    • D:\ClionProject\exception\cmake-build-debug\exception.exe
      succeed in catching the const char* exception: there is an error type string
      succeed in catching the char* exception: there is an error type string
      succeed in catching the string pointer exception: there is an error type string
      ​
      Process finished with exit code 0

  • 抛出自定义类型的异常:

  • 简单定义一个MyException的类型

    • 分别定义其构造析构以及一个拷贝构造。

    • 定义一个成员变量id_,并定义一个public的成员函数用于获取id值。

    • 在构造函数中初始化id_为0而拷贝构造函数中初始其为1,由此来分辨在这个测试中的生命周期。

    • 再各个函数中输出当前所在函数的名称,析构函数中输出自己从那个构造方法得出(根据之前的id_成员实现)。

    • 我们在异常抓取时使用pass by value的方式,来查看一下拷贝发生的时机。

    • 下面是我的代码:

    • #include <iostream>
      #include <string>
      ​
      class MyException{
      public:MyException(){this->id_ = 0;std::cout << "constructor" << std::endl;}MyException(const MyException& other){this->id_ = 1;std::cout << "copy constructor" << std::endl;}~MyException(){std::cout << "destructor " << ((this->getId()==0) ? "constructor" : "copy constructor") << std::endl;}[[nodiscard]]int getId()const{return this->id_;}
      private:int id_;
      };
      ​
      void test_4_class_exception(){try{throw MyException();}catch(MyException e){std::cout << "caught an object error: "<< ((e.getId()==0) ? "constructor" : "copy constructor") << std::endl;}
      }
      ​
      int main() {
      ​test_4_class_exception();
      ​return 0;
      }

    • 其运行结果如下:

    • D:\ClionProject\exception\cmake-build-debug\exception.exe
      constructor
      copy constructor
      caught an object error: copy constructor
      destructor copy constructor
      destructor constructor
      ​
      Process finished with exit code 0

    • 我们来根据这个输出结果大致分析一下这个调用的时机

      • 第一条发生在try 语句中的临时变量构造中。

      • 第二条时在传递exception时在catch中参数的一个拷贝,这是因为我们使用了pass by value的情况。

      • 第三条表示id_值为1,这意味着这个传递过来的时一个拷贝的对象。

      • 四条五条直接反映了析构调用的顺序,类似栈先进后出。

  • 类对象类型异常抛出的性能优化

    • 继续使用刚才的代码,但是这一次我们线在throw中声明一个对象然后再把它抛出,然后继续使用pass by value 方式接收异常:

    • #include <iostream>
      #include <string>
      ​
      class MyException{
      public:MyException(){this->id_ = 0;std::cout << "constructor" << std::endl;}MyException(const MyException& other){this->id_ = 1;std::cout << "copy constructor" << std::endl;}~MyException(){std::cout << "destructor " << ((this->getId()==0) ? "constructor" : "copy constructor") << std::endl;}[[nodiscard]]int getId()const{return this->id_;}
      private:int id_;
      };
      ​
      void test_4_class_exception(){try{MyException exc;throw exc;}catch(MyException e){std::cout << "caught an object error: "<< ((e.getId()==0) ? "constructor" : "copy constructor") << std::endl;}
      }
      ​
      int main() {
      ​test_4_class_exception();
      ​return 0;
      }

    • 输出的结果如下:

    • D:\ClionProject\exception\cmake-build-debug\exception.exe
      constructor
      copy constructor
      destructor constructor
      copy constructor
      caught an object error: copy constructor
      destructor copy constructor
      destructor copy constructor
      ​
      Process finished with exit code 0

    • 一下子出现了很多的输出,说明调用了很多次的拷贝,这无异于 一种资源浪费,我们来分析一下这个输出。

      • 前面三条输出,第一条就是正常的构造,然后在抛出时会调用一个拷贝构造函数,并将此靠背后的对象传递给下一层。

      • 与此同时前面的局部变量被销毁调用了一个析构函数。

      • 由于我们使用的时pass by value,这会在抓取异常时再次调用一次拷贝构造函数,当然我们最后传入的对象来自于拷贝因此有了四五条的输出。

      • 六条七条就是把这两个对象全部销毁,虽然没有什么有价值的信息,但是在之前的测试中我们已经知道他们的析构顺序类似于栈,先进后出。

    • 那么如何优化呢?

      • 首先我们知道,在抛出异常时最佳办法就是直接抛出一个临时变量,这样会减少一次拷贝。

      • 而在抓取异常时我们使用pass by reference会再次减少一次拷贝构造的调用。

      • 改良后的代码如下:

      • class MyException{
        public:MyException(){this->id_ = 0;std::cout << "constructor" << std::endl;}MyException(const MyException& other){this->id_ = 1;std::cout << "copy constructor" << std::endl;}~MyException(){std::cout << "destructor " <<  ((this->getId()==0) ? "constructor" : "copy constructor") << std::endl;}[[nodiscard]]int getId()const{return this->id_;}
        private:int id_;
        };
        ​
        void test_4_class_exception(){try{//MyException exc;throw MyException();}catch(MyException& e){std::cout << "caught an object error: "<< ((e.getId()==0) ? "constructor" : "copy constructor") << std::endl;}
        ​
        }
        ​
        ​
        int main() {test_4_class_exception();
        ​return 0;
        }

      • 运行结果如下,只是调用了一次构造函数并在接收异常后析构,被抓取的对象也只是经过构造函数得来的:

      • D:\ClionProject\exception\cmake-build-debug\exception.exe
        constructor
        caught an object error: constructor
        destructor constructor
        ​
        Process finished with exit code 0
      • 如果抛出的是一个来自堆内存中的异常类型呢?

      • 那么类似string*,他会抛出一个类对象的指针,这样接受也要用相应的形参,还有就是不要忘记堆内存的释放。

      • class MyException{
        public:MyException(){this->id_ = 0;std::cout << "constructor" << std::endl;}MyException(const MyException& other){this->id_ = 1;std::cout << "copy constructor" << std::endl;}~MyException(){std::cout << "destructor " <<  ((this->getId()==0) ? "constructor" : "copy constructor") << std::endl;}[[nodiscard]]int getId()const{return this->id_;}
        private:int id_;
        };
        ​
        void test_4_class_exception(){try{//MyException exc;throw new MyException();}catch(MyException& e){std::cout << "caught an object error: "<< ((e.getId()==0) ? "constructor" : "copy constructor") << std::endl;}catch(MyException* e){std::cout << "caught an object pointer error: "<< ((e->getId()==0) ? "constructor" : "copy constructor") << std::endl;delete e;}
        ​
        }
        ​
        ​
        int main() {test_4_class_exception();
        ​return 0;
        }
      • 输出结果如下:

      • D:\ClionProject\exception\cmake-build-debug\exception.exe
        constructor
        caught an object pointer error: constructor
        destructor constructor
        ​
        Process finished with exit code 0

异常处理与继承

  • 异常可以定义成类 ,因此就会涉及到继承和多态的使用,这也是cpp中的核心功能。

  • 一个小案例:设计一个数组容器Vector, 重载[]操作符号,数组初始化时对数组 个数进行 有效化的检查。

    • index<0 抛出异常 errNegativeException

    • index=0 抛出异常 errZeroException

    • index>1000 抛出异常 errOverLargeException

    • index<10 抛出异常 errOverSmallException

    • 所有的异常类继承自errSizeException,在父类中要定义有参构造,并实现一个虚函数virtual void printError()用于输出相应的错误。

  • 首先是Vector类,我直接上代码就不讲解了,这里没有使用任何的模板编程。顺便把改写的异常处理也直接加进去了。首先时头文件:

  • //
    // Created by herryao on 2024/1/25.
    //
    ​
    #ifndef EXCEPTION_INHERITANCE_VECTOR_H
    #define EXCEPTION_INHERITANCE_VECTOR_H
    ​
    ​
    class Vector {
    public:Vector(int size=128);Vector(const Vector& other);[[nodiscard]] int getLength()const;int& operator[](int indx);int operator[](int indx) const;~Vector();
    private:int *list_;int length_;
    ​
    };
    ​
    ​
    #endif //EXCEPTION_INHERITANCE_VECTOR_H
  • 然后是源文件,值得注意的是在这里我重载了两种[]的方法,那么在这两种成员方法中我们都要进行异常处理,按照之前的项目要求我已经在方法中给出了相应的声明,利用一个pass by reference 的方法调用了多态,降低了 代码的重复。

  • //
    // Created by herryao on 2024/1/25.
    //
    ​
    #include "Vector.h"
    #include "errSizeException.h"
    ​
    int Vector::operator[](int indx) const {if(indx==0){throw errorZeroException(indx);}else if(indx > 1000){throw errorOverLargeException(indx);}else if(indx > 0 && indx < 10){throw errorOverSmallException(indx);}else if(indx < 0){throw errorNegativeException(indx);}return this->list_[indx];
    }
    ​
    Vector::Vector(int size) {this->list_ = new int[size];this->length_ = size;
    }
    ​
    int Vector::getLength() const {return this->length_;
    }
    ​
    int &Vector::operator[](int indx) {if(indx==0){throw errorZeroException(indx);}else if(indx > 1000){throw errorOverLargeException(indx);}else if(indx > 0 && indx < 10){throw errorOverSmallException(indx);}else if(indx < 0){throw errorNegativeException(indx);}return this->list_[indx];
    }
    ​
    Vector::Vector(const Vector &other) {this->list_ = new int[other.getLength()];for(int i=0; i<other.getLength(); ++i){this->list_[i] = other.list_[i];}this->length_ = other.length_;
    }
    ​
    Vector::~Vector() {delete []this->list_;this->length_ = 0;
    }
    ​

  • 然后是异常处理。

  • 直接上代码,原理很简单,就是在异常类中顺便保存一下出错的索引数据并把它输出出来。这个索引数据就保存在父类的一个保护成员中,然后要在有参构造中初始化这个成员变量。所有实现都放在头文件了,代码如下:

  • //
    // Created by herryao on 2024/1/25.
    //
    ​
    #ifndef EXCEPTION_INHERITANCE_ERRSIZEEXCEPTION_H
    #define EXCEPTION_INHERITANCE_ERRSIZEEXCEPTION_H
    #include <iostream>
    ​
    ​
    class errorSizeException{
    public:errorSizeException(int size):size_(size){}virtual void printError()const = 0;
    protected:int size_;
    };
    ​
    class errorZeroException:public errorSizeException{
    public:errorZeroException(int size): errorSizeException(size){}void printError()const override{std::cout << "ZeroException!" << this->size_ << std::endl;}
    };
    ​
    class errorOverLargeException:public errorSizeException{
    public:errorOverLargeException(int size): errorSizeException(size){}virtual void printError()const override{std::cout << "OverlargeException!" << this->size_ << std::endl;}
    };
    ​
    class errorOverSmallException:public errorSizeException{
    public:errorOverSmallException(int size): errorSizeException(size){}virtual void printError()const override{std::cout << "OverSmallException!" << this->size_ << std::endl;}
    };
    ​
    class errorNegativeException:public errorSizeException{
    public:errorNegativeException(int size): errorSizeException(size){}virtual void printError()const override{std::cout << "NegativeException!" << this->size_ << std::endl;}
    };
    ​
    #endif //EXCEPTION_INHERITANCE_ERRSIZEEXCEPTION_H
    
  • 最后是我们的主函数 文件,像往常一样我定义了测试函数进行相应的测试这几种相应的异常 我都进行了测试:

  • #include <iostream>
    #include "Vector.h"
    #include "errSizeException.h"
    ​
    void testExcep(int indx){//default size = 1024Vector v;try{v[indx];}catch(errorSizeException& e){e.printError();}
    }
    int main() {testExcep(5);testExcep(100000);testExcep(0);testExcep(-11111);return 0;
    }

  • 最后的输出结果如下,意味着我们的代码符合要求了,实现了异常的多态调用:

  • D:\ClionProject\exception_inheritance\cmake-build-debug\exception_inheritance.exe
    OverSmallException!5
    OverlargeException!100000
    ZeroException!0
    NegativeException!-11111
    ​
    Process finished with exit code 0

异常处理的基本思想

  • C++的异常处理机制使得异常的引发和异常的处理不必在同一个函数中,这样底层的函数可以着重解决具体问题,而不必过多的考虑异常的处理。上层调用者可以再适当的位置设计对不同类型异常的处理。

  • 异常是专门针对抽象编程中的一系列错误进行处理的,C++中不能借助函数机制实现异常,因为栈结构的本质是先进后出,依次访问,无法进行跳跃,但错误处理的特征却是遇到错误信息就想要转到若干级之上进行重新尝试,因此异常处理是必要的,也就此诞生。

致谢
  • 感谢Martin老师的课程。

  • 感谢各位的支持,祝大家越来越强,一起进步。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/646905.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vue3中使用markdown编辑器

首先安装 npm i md-editor-v3 Setup 模板 <template><MdEditor v-model"text" /> </template><script setup> import { ref } from vue; import { MdEditor } from md-editor-v3; import md-editor-v3/lib/style.css;const text ref(Hell…

R语言-检验正态性

1.为什么要检验正态性 首先需要明确正态性与正态分布是有区别的&#xff0c;正态分布&#xff08;标准分布&#xff09;是统计数据的分布方式&#xff0c;是个钟形曲线&#xff0c;已平均值为对称轴&#xff0c;数据在对称轴两侧对称分布。正态性是检验实际数据与标准正态分布…

消息中间件之八股面试回答篇:一、问题概览+MQ的应用场景+RabbitMQ如何保证消息不丢失(生产者确认机制、持久化、消费者确认机制)+回答模板

问题概览 目前主流的消息队列技术&#xff08;MQ技术&#xff09;分为RabbitMQ和Kafka&#xff0c;其中深蓝色为只要是MQ&#xff0c;一般都会问到的问题。浅蓝色是针对RabbitMQ的特性的问题。蓝紫色为针对Kafka的特性的问题。 MQ的应用场景 MQ主要提供的功能为&#xff1a;异…

Linux shell编程学习笔记42:hdparm命令

ChatGPT 和文心一言哪个更好用&#xff1f; 从智能回复、语言准确性、知识库丰富度等方面比较&#xff0c;两大AI助手哪个更胜一筹&#xff1f;快来和我们分享一下你的看法吧~ 0 前言 获取硬盘序列号是信息资产管理和信息安全检测中经常要收集的信息&#xff0c;对于Linux来说…

Unity - 将项目转为HDRP

Camera window -> Package Manager 之后会出现HDRP向导窗口&#xff0c;均点击修复。 在Edit中&#xff0c;更改项目中的材质

景联文科技大模型数据集更新!教育题库新增高质量数学题、逻辑推理题及英文题

苏格拉底曾以“点燃火焰”的理念来诠释教育。随着大语言模型在教育中的不断应用&#xff0c;教育与AI的深度融合&#xff0c;让我们看到了“点燃火焰”的理念的更多可能性。 大语言模型可以通过与学生的互动&#xff0c;为他们提供个性化的学习体验&#xff0c;更好地满足学习需…

本地仓库如何与远程仓库进行关联

目录 设置Git 全局设置: 创建一个远程仓库 创建本地仓库 连接远程仓库 查看远程仓库origin的关联信息 查看所有远程仓库 切换远程仓库 设置Git 全局设置: git config --global user.name "your name" git config --global user.email "your email163.co…

目标检测数据集 - MS COCO

文章目录 1. 数据集介绍2. 使用pycocotools读取数据3. 验证mAP 论文&#xff1a;Microsoft COCO: Common Objects in Context 网址&#xff1a;https://arxiv.org/abs/1405.0312 官网&#xff1a;https://cocodataset.org/ 1. 数据集介绍 MS COCO是一个非常大型&#xff0c;且…

音频特效SDK,满足内容生产的音频处理需求

美摄科技&#xff0c;作为音频处理技术的佼佼者&#xff0c;推出的音频特效SDK&#xff0c;旨在满足企业内容生产中的音频处理需求。这款SDK内置多种常见音频处理功能&#xff0c;如音频变声、均衡器、淡入淡出、音频变调等&#xff0c;帮助企业轻松应对各种音频处理挑战。 一…

【服务器】服务器四个网口有几块网卡?

具有四个网口的服务器的网卡数量可能有点混乱。乍一看&#xff0c;您可能会假设服务器有四块网卡&#xff0c;每个端口一块。然而&#xff0c;这并非总是如此。在本文中&#xff0c;我们将分析具有四个网络端口的服务器的不同配置以及它可能有多少个网卡。 一个网卡&#xff0…

2024/1/24 图的基本应用

目录 查找文献 图的遍历 查找文献 P5318 【深基18.例3】查找文献 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn) 思路&#xff1a;这道题就是先建图&#xff0c;然后dfs深搜输出&#xff0c;bfs宽搜输出就行了 完整代码&#xff1a; #include <bits/stdc.h> #defi…

网安培训第二期——sql注入+中间件+工具

文章目录 宽字节注入插入注入二次注入PDO模式(动态靶机&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;)sql注入读取文件sql注入导出文件linux命令 10.12笔记sqlmapsqlmap参数 10.13笔记sqlmap 文件读写前后缀常用tamper及适用场景 10.…

【Java】SpringMVC路径写法

1、多级路径 ✅类路径和方法路径都可以写成多级 ✅其中&#xff0c;类路径写在方法路径前面 ✅与Servlet不同&#xff0c;SpringMVC中写不写“/”都可以 RequestMapping("/hello/t1") RestController public class HelloSpring {RequestMapping( value "world…

不学前沿技术与朽木浮草何异 ?Java11新特性

不学前沿技术与朽木浮草何异 &#xff1f;Java11新特性 于 2018 年 9 月 25 日正式发布&#xff0c;这是很重要的一个版本&#xff01;Java 11 和 2017 年 9 月份发布的 Java 9 以及 2018 年 3 月份发布的 Java 10 相比&#xff0c;其最大的区别就是&#xff1a;在长期支持(Lo…

013:获取K线图,增加周期可选

改进《001:如何获取A股个股的前复权K线数据》&#xff0c;增加周期可选。 代码&#xff1a; import tkinter as tk from tkinter import messagebox from tkcalendar import Calendar import pandas as pd import requests from urllib.parse import urlencodedef gen_secid(…

Docker:6种网络配置详解浅介

在Docker中&#xff0c;网络配置是一个重要的主题&#xff0c;因为容器需要与其他容器或外部网络进行通信。Docker提供了多种网络模式和配置选项&#xff0c;以便在不同的场景下满足用户的需求。 本文介绍这些网络模式的区别以及配置&#xff0c;相信看完以后你能够掌握Docker网…

100 道 Linux 面试题 附答案(二)

五、编程题 判断一文件是不是字符设备文件&#xff0c;如果是将其拷贝到 /dev 目录下&#xff1f; #!/bin/bash read -p "Input file name: " FILENAME if [ -c "$FILENAME" ];thencp $FILENAME /dev fi添加一个新组为 class1 &#xff0c;然后添加属于这…

16、Kafka ------ SpringBoot 整合 Kafka (配置 Kafka 属性 及对应的 属性处理类 解析)

目录 配置 Kafka 及对应的 属性处理类配置KafkaKafka配置属性的约定代码演示生产者相关的配置消费者相关的配置 代码&#xff08;配置文件&#xff09;application.properties 配置 Kafka 及对应的 属性处理类 配置Kafka spring.kafka.* 开头的配置属性&#xff0c;这些属性将由…

Python如何按指定列的空值删除行?

目录 1、按指定列的空值删除行2、滑动窗口按指定列的值填充最前面的缺失值 1、按指定列的空值删除行 数据准备&#xff1a; df pd.DataFrame({C1: [1, 2, 3, 4], C2: [A, np.NaN, C, D], C3: [V1, V2, V3, np.NaN]}) print(df.to_string()) C1 C2 C3 0 1 A V1 1 …

写作的金字塔原则

起源 芭芭拉明托 (Barbara Minto) 是 20 世纪 70 年代麦肯锡公司培训主管&#xff0c;她创立了金字塔原则。1963 年从哈佛商学院毕业后&#xff0c;明托加入了麦肯锡公司。在前往该公司位于巴黎和杜塞尔多夫的办公室出差时&#xff0c;她遇到了与她在美国和英国见过的同样的写作…