String 类和 STL (Standard Template Library)

C++ STL(标准模板库,Standard Template Library)简介 容器(Containers)提供存储和管理数据的结构,如动态数组、链表、哈希表等。算法(Algorithms)提供对容器进行操作的通用算法,如排序、查找、复制等。迭代器(Iterators)提供一种统一的方式来访问容器中的元素,连接容器和算法。 阅读详情


一. string 类

  •        很多应用程序都需要处理字符串。C语言在string.h(在++中为cstring)中提供了一系列的字符串函数,很多早期的C++实现为处理字符串提供了自己的类。

  •         string类是由头文件string支持的(以头文件string.h和cstring支持对C风格字符串进行操纵的C库字符串函数,但不支持string类)。要使用类,关键在于知道它的公有接口,而string类包含大量的方法,其中包括了若干构造函数,用于将字符串赋给变量、合并字符串、比较字符串和访问各个元素的重载运算符以及用于在字符串中查找字符和子字符串的工具等。以string类包含的内容很多。

1. 构造字符串

  •        先来看string的构造函数。毕竟,对于类而言,最重要的内容之一是,有哪些方法可用于创建其对象。程序清单1使用了string的7个构造函数(用ctor标识,这是传统C++中构造函数的缩写)。表1简要地描述了这些构造函数,它首先按顺序简要描述了程序清单1使用的7个构造函数,然后列出了C++11新增的两个构造函数。使用构造函数时都进行了简化,即隐藏了这样一个事实:string实际上是模板具体化basic_string<char>的一个typedef,同时省略了与内存管理相关的参数。 size_type是一个依赖于实现的整型,是在头文件string中定义的。string类将string::npos定义为字符串的最大长度,通常为unsigned int的最大值。以表格中使用缩写NBTS(null终止string)来表示以空字符结束的字符串一一传统的C字符串。

    表1 string类的构造函数

    构 造 函 数

    描述

    string(const char * s)

    将string对象初始化为s指向的NBTS

    string(size_type n, char c)

    创建一个包含n个元素的string对象,其中每个元素都被初始化为字符c

    string(const string & str)

    将一个string对象初始化为string对象str(复制构造函数)

    string()

    创建一个默认的string对象,长度为0(默认构造函数)

    string(const char * s, size_type n)

    将string对象初始化为s指向的NBTS的前n个字符,即使超过了NBTS结尾

    template<class Iter>
    string(Iter begin, Iter end)

    将string对象初始化为区间[begin, end)内的字符,其中begin和end的行为就像指针,用于指定位置,范围包括begin在内,但不包括end

    string(const string & str, size_type pos, size_type n = npos)

    将一个string对象初始化为对象str中从位置pos开始到结尾的字符,或从位置pos开始的n个字符

    string(string && str) noexcept

    这是C++11新增的,它将一个string对象初始化为string对象str,并可能修改str(移动构造函数)

    string(initializer_list<char> il)

    这是C++11新增的,它将一个string对象初始化为初始化列表il中的字符

    程序清单1 :
    #include <iostream>
    #include <string>
    // using string constructors
    int main()
    {
        using namespace std;
        string one("Lottery Winner!"); // ctor #1
        cout << one << endl;           // overloaded <<
        string two(20, '$');           // ctor #2
        cout << two << endl;
        string three(one);             // ctor #3
        cout << three << endl;
        one += " Oops!";               // overloaded +=
        cout << one << endl;
        two = "Sorry! That was ";      //will Clean up the original string in object two
        three[0] = 'P';
        string four;                   // ctor #4
        four = two + three;            // overloaded +, =
        cout << four << endl;
        char alls[] = "All's well that ends well";
        string five(alls,20);          // ctor #5
        cout << five << "!\n";
        string six(alls+6, alls + 10); // ctor #6
        cout << six << ", ";
        string seven(&five[6], &five[10]); // ctor #6 again
        cout << seven << "...\n";
        cout << "Now four is :" << four << endl;
        string eight(four, 7, 16);     // ctor #7
        cout << eight << " in motion!" << endl;
        system("pause");
        return 0;
    }
    

    程序清单1 的输出:

    Lottery Winner!
    $$$$$$$$$$$$$$$$$$$$
    Lottery Winner!
    Lottery Winner! Oops!
    Sorry! That was Pottery Winner!
    All's well that ends!
    well, well...
    Now four is :Sorry! That was Pottery Winner!
    That was Pottery in motion!
    Press any key to continue . . .
    

2. string类输入

  • 有哪些输入方式可用呢? 对于C风格的字符串, 有3种方式:

    char info[100];
    cin >> info;             // read a word
    cin.getline(info, 100);  // read a line, discard \n
    cin.get(info, 100);      // read a line, leave \n in queue
    
  • 对于string 对象 有两种方式:

    string stuff;
    cin >> stuff;        // read a word
    getline(cin, stuff); // read a line, discard \n
    
  • 两个版本的getline() 都有一个可选参数, 用于指定使用什么字符作为读取的边界;

    cin.getline(info,100,':'); // read up to :, discard :
    getline(cin,stuff, ':');   // read up to :, discard :
    

    对于string版本的getline() 能够自动调整目标string 对象的大小, 使之刚好能存储输入的字符:

    char fname[10];
    string lname;
    cin >> fname;            // could be a problem if input size > 9 characters
    cin >> lname;            // can read a very, very long word
    cin.getline(fname, 10);  // may truncate input
    getline(cin, fname);     // no truncation
    

    自动调整大小的功能让 string版本的getline() 不需要指定要读取多少个字符的参数

  • string 版本的 getline() 从输入流中读取字符, 并将其放入目标string 中, 直到发生下面几种情况:

    • 到达文件尾的输入流的eofbit将被设置,这意味着方法fail()和eof()都将返回true;
    • 遇到分界字符(默认为\n) 在这种情况下, 将把分界字符从输入流中删除,但不存储它;
    • 读取的字符数达到最大允许值(string::npos和可供分配的内存字节数中较小的一个) 在这种情况下,将设置输入流的failbit,这意味着方法fail()将返回true。

    eofbit fail()等与 流状态 相关, 将在 ~ C++输入输出和文件 -> 三. 使用cin进行输入 -> 2. 流状态 ~ 中讲解

3. 使用字符串

  • 字符串比较
    string 类对全部6个关系运算符都进行了重载, 如果机器排列序列为ASCII码, 那么数字字符 < 大写字符 < 小写字符;
    对于每个关系运算符, 都以三种方式被重载, 以便将string对象和 另一个string对象,C风格字符串 进行比较 :

    #include <iostream>
    #include <exception>
    int main()
    {
        using namespace std;
        string snake1("cobra");
        string snake2("coaal");
        char snake3[20] = "cobra";
        if (snake1 < snake2) // operator<(const string &, const string &)
        {
            cout << "snake1 < snake 2" << endl;
        }
        if (snake1 == snake3) // operator==(const string &, const char *)
        {
            cout << "snake1 == snake3" << endl;
        }
    
        if (snake3 != snake2) // operator!=(const char *, const string &)
        {
            cout << "snake3 != snake2" << endl;
        }
        system("pause");
        return 0;
    }
    

    size() 和 length() 都返回字符串的字符数
    length()成员来自较早版本的string类, 而size()则是为STL兼容性而添加的

  • 字符串查找
    string::npos是字符串可存储的最大字符数, 通常是无符号int或long的最大取值;

    表2 重载的find()方法

    方 法 原 型

    描 述

    size_type find(const string & str,
    size_type pos = 0)const

    从字符串的pos位置开始,查找子字符串str。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string :: npos

    size_type find(const char * s,
    size_type pos = 0)const

    从字符串的pos位置开始,查找子字符串s。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string :: npos

    size_type find(const char * s,
    size_type pos, size_type n)

    从字符串的pos位置开始,查找s的前n个字符组成的子字符串。如果找到,则返回该子字符串首次出现时其首字符的索引;否则,返回string :: npos

    size_type find(char ch,
    size_type pos = 0)const

    从字符串的pos位置开始,查找字符ch。如果找到,则返回该字符首次出现的位置;否则,返回string :: npos

    string 库还提供了相关的方法: rfind()、find_first_of()、find_last_of()、find_first_not_of()和find_last_not_of(),它们的重载函数特征标都与find()方法相同。rfind()方法查找子字符串或字符最后一次出现的位置;find_first_of()方法在字符串中查找参数中任何一个字符首次出现的位置。例如,下面的语句返回 r 在“cobra”中的位置(即索引3),因为这是“hark”中各个字母在“cobra”首次出现的位置:
    int where = snake1.find_first_of("hark");
    

    find_last_of()方法的功能与此相同,只是它查找的是最后一次出现的位置。因此,下面的语句返回a在“cobra”中的位置:

    int where = snake1.find_last_of("hark");
    

    find_first_not_of()方法在字符串中查找第一个不包含在参数中的字符,因此下面的语句返回c在“cobra”中的位置,因为“hark”中没有c:

    int where = snake1.find_first_not_of("hark");
    

4. 其他string类方法

  • 很多, 就萝莉一些, 再挑几个讲. 其他的用到的时候就知道了

    a) =,assign() //赋以新值 
    b) swap() //交换两个字符串的内容 
    c) +=,append(),push_back() //在尾部添加字符 
    d) insert() //插入字符 
    e) erase() //删除字符 
    f) clear() //删除全部字符 
    g) replace() //替换字符 
    h) + //串联字符串 
    i) ==,!=,<,<=,>,>=,compare() //比较字符串 
    j) size(),length() //返回字符数量 
    k) max_size() //返回字符的可能最大个数 
    l) empty() //判断字符串是否为空 
    m) capacity() //返回重新分配之前的字符容量 
    n) reserve() resize()//保留一定量内存以容纳一定数量的字符 
               //resize() 会重置size和length 参数如果小于当前的size,则截短,大于则扩充
        //resize() 扩充时默认是用'\0'填充, 第二个可选参数可指定用什么字符填充
    	//resize()减少size时 不会影响capacity
    o) [], at() //存取单一字符  at()索引无效时,会抛出out_of_range异常
    p) >>,getline() //从stream读取某值 
    q) << //将谋值写入stream 
    r) copy() //将某值赋值为一个C_string 
    s) c_str() //将内容以C_string返回  不可修改
    t) data() //将内容以字符序列指针形式返回 可修改
    u) substr() //返回某个子字符串 
    v)查找函数 
    w)begin() end() //提供类似STL的迭代器支持 
    x) rbegin() rend() //逆向迭代器 
    y) get_allocator() //返回配置器 
      //string 中 capacity 最小 15
    z) shrink_to_fit() //A non-binding request to reduce capacity() to size() 
    
  • compare 返回值意义(吾用区间表示法表示):[小于,0,大于] , 0:相等

    string s("abcd"); 
    s.compare("abcd"); //返回0 
    s.compare("dcba"); //返回一个小于0的值 
    s.compare("ab"); //返回大于0的值 
    s.compare(s); //相等 
    //参数1:下标 2:字符个数 3:比较的对象 4:下标 5:字符个数
    s.compare(0,2,s,2,2); //用"ab"和"cd"进行比较 小于零 
    //参数1:下标 2:字符个数 3:比较的对象 4:字符个数
    s.compare(1,2,"bcx",2); //用"bc"和"bc"比较。
    
  • assign 重新分配

    s.assign(str); //字面意思
    //参数1:目标 2:下标 3:字符数
    s.assign(str,1,3);//如果str是"iamangel" 就是把"ama"赋给字符串 
    s.assign(str,2,string::npos);//把字符串str从索引值2开始到结尾赋给s 
    s.assign("gaint"); //字面意思
    s.assign("nico",5);//把’n’ ‘I’ ‘c’ ‘o’ ‘’赋给字符串 
    s.assign(5,'x');//把五个x赋给字符串 
    
  • append 附加

    s.append(str); 
    s.append(str,1,3);//不解释了 同前面的函数参数assign的解释 
    s.append(str,2,string::npos)//
    s.append("my name is jiayp"); 
    s.append("nico",5); 
    s.append(5,'x'); 
    s.push_back('a');//这个函数只能增加单个字符
    
  • insert 插入

    s.insert(0,"my name");
    s.insert(1, "m");
    s.insert(1,str); 
    
  • replace erase 替换和擦除

    s.replace(1,2,"nternationalizatio");//从索引1开始的2个替换成后面的C_string或string对象
    s.erase(13);//从索引13开始往后全删除 
    s.erase(7,5);//从索引7开始往后删5个 
    
  • substr 返回子字符串(新的string)

    s.substr();//返回s的全部内容 
    s.substr(11);//从索引11往后的子串 
    s.substr(5,6);//从索引5开始6个字符 
    
  • copy 复制并替换目标中原有的字符

    char str1[20] = "Hello";
    char str2[20] {0};
    string sl = "World";
    //参数1:目标对象 2:要copy的字符数 3:从sl的下标?开始
    sl.copy(str1, 5, 2);//
    cout << str1 << endl;
    
  • 方法capacity()返回当前分配给字符串的内存块的大小,而reserve()方法让您能够请求增大内存块

    #include <iostream>
    #include <string>
    int main()
    {
        using namespace std;
        string empty;
        string small = "bit";
        string larger = "Elephants are a girl's best friend";
        cout << "Sizes:\n";
        cout << "\tempty: " << empty.size() << endl;
        cout << "\tsmall: " << small.size() << endl;
        cout << "\tlarger: " << larger.size() << endl;
        cout << "Capacities:\n";
        cout << "\tempty: " << empty.capacity() << endl;
        cout << "\tsmall: " << small.capacity() << endl;
        cout << "\tlarger: " << larger.capacity() << endl;
        empty.reserve(50);
        cout << "Capacity after empty.reserve(50): "
             << empty.capacity() << endl;
        return 0;
    }
    
  • 如果您有string对象,但需要C风格字符串,该如何办呢?

    string filename;
    filename.c_str(); //返回c风格字符串
    
  • 如果你需要string对象提供一个可供修改内容字符串的地址 以便传入需要修改该地址上C风格字符串的函数
    可以使用data()成员函数返回可修改的C字符串地址, 但你必须十分小心:很多成员函数行为都将变异

    • string 无法知道你对C风格字符做了什么修改, 因为你不是通过string类提供的方法修改的
      这意味着size() length()成员函数都返回原先的值
    • 经过测试, 无参构造且不调用reserve()扩容的情况下, 默认分配给内部C字符串指针29个字节的内存还有一个留给’\0’.
    • 不应该保留data() 成员函数返回的指针, 一旦使用reserve()扩容, 这个地址随时可能改变 (realloc都保不住)
    • 如果要继续使用该string对象, 你应该使用类似s.append(s.data());能使它的成员恢复正常的方法
    • 在把string对象内部C字符串指针传给要修改C字符串风格的函数前, 应调用reserve()扩大到足够的容量
    • 你可以用这些代码来测试: (我发现现代编译器很离谱,居然自己调整这些, 我现在不确定分配给内部C字符串的内存一开始是多少了)
      #include <iostream>
      #include <fstream>
      #include <string>
      #include <cstring>
      #include <memory>
      #include <iomanip>
      #include <vector>
      using namespace std;
      int main()
      {
          string buf;
          cout << setw(16) << left;
          cout << setw(16) << "before buf size():" << buf.size() << endl;
          cout << setw(16) << "before buf capacity():" << buf.capacity() << endl;
      
          cin.get(buf.data(), 100);
          //    buf.append(buf.data());
          //    buf.assign(buf.data());
          //    buf = buf.data();
          cout << setw(16) << "buf size():" << buf.length() << endl;
          cout << setw(16) << "buf capacity():" << buf.capacity() << endl;
          cout << setw(16) << "empty():" << boolalpha << buf.empty() << endl;
          cout << endl;
          cout << setw(16) << "buf:" << setw(20) << buf << "address :" << &buf << endl;
          cout << setw(16) << "buf.c_str():" << setw(20) << buf.c_str() << "address :" << (int*)buf.c_str() << endl;
          cout << setw(16) << "buf.data():" << setw(20) << buf.data() << "address :" << (int*)buf.data() << endl;
          cout << setw(16) << "strlen(buf.c_str()):" << strlen(buf.c_str()) << endl;
          cout << endl;
          cout << "cin.fail():" << cin.fail() << endl;
          cout << "cin.eof():" << cin.eof() << endl;
          cout << "cin.bad():" << cin.bad() << endl;
          system("pause");
          return 0;
      }
      
      • 如果使用无参默认构造string, 则修改data()上的数据后使用s.append(s.data());是安全的
      • 如果不确定内部分配给data()函数返回的指针多少个字节的内存, 为避免越界, 应使用 reserve()扩容
  • string 对象中 data()和c_str()成员函数返回的是同一个地址, 它的所有成员都是用来限定string对象单独维护的一个字符串的, 而不是data()和c_str()返回的字符串. 如果说你在外部增加或修改了data()中的字符, string对象变现(指变成字符串)时 会按当前内部成员size截取 data()上的字符放入那个隐藏维护的字符串地址上 并在size+1处添加’\0’ .

5. 字符串种类

  • 本节将string类看作是基于char类型的。事实上,正如前面指出的,string库实际上是基于一个模板类的:

    template<class charT, class traits = char _traits<charT>,
            class Allocator = allocator<charT> >
    basic_string {...};
    
  • 模板basic_string有4个具体化(特化),每个具体化都有一个typedef名称:

    typedef basic_string<char> string;
    typedef basic_string<wchar_t> wstring;
    typedef basic_string<char16_t> u16string;   // C++11
    typedef basic_string<char32_t> u32string ; // C++11
    

    这让您能够使用基于类型wchar_t、char16_t、char32_t和char的字符串。甚至可以开发某种类似字符的类,并对它使用basic_string类模板(只要它满足某些要求)。traits类描述关于选定字符类型的特定情况,如如何对值进行比较。对于wchar_t、char16_t、char32_t和char类型,有预定义的char_traits模板具体化,它们都是traits的默认值。Allocator是一个管理内存分配的类。对于各种字符类型,都有预定义的allocator模板具体化,它们都是默认的。它们使用new和delete。

二. 智能指针

  • 要创建智能指针, 必须包含头文件 memory

    template<class X> class auto_ptr {
    public:
        explicit auto_ptr(X* p =0) throw();
    ...};
    
    auto_ptr<double> pd(new double); // pd an auto_ptr to double
                                     // (use in place of double * pd)
    auto_ptr<string> ps(new string); // ps an auto_ptr to string
                                     // (use in place of string * ps)
    
  • auto_ptr 已被弃用, 应使用功能更明确的shared_ptr 和 unique_ptr

  • shared_ptr

    表 3 shared_ptr<T>模板类常用成员方法
    成员方法名 功 能
    operator=() 重载赋值号,使得同一类型的 shared_ptr 智能指针可以相互赋值。
    operator*() 重载 * 号,获取当前 shared_ptr 智能指针对象指向的数据。
    operator->() 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。
    swap() 交换 2 个相同类型 shared_ptr 智能指针的内容。
    reset() 当函数没有实参时,该函数会使当前 shared_ptr 所指堆内存的引用计数减 1,同时将当前对象重置为一个空指针;当为函数传递一个新申请的堆内存时,则调用该函数的 shared_ptr 对象会获得该存储空间的所有权,并且引用计数的初始值为 1。
    get() 获得 shared_ptr 对象内部包含的普通指针。
    use_count() 返回同当前 shared_ptr 对象(包括它)指向相同的所有 shared_ptr 对象的数量。
    unique() 判断当前 shared_ptr 对象指向的堆内存,是否不再有其它 shared_ptr 对象再指向它。
    operator bool() 判断当前 shared_ptr 对象是否为空智能指针,如果是空指针,返回 false;反之,返回 true。
  • 空的 shared_ptr 指针,其引用计数为 0,而不是 1。

    std::shared_ptr<int> p1;             //不传入任何实参
    std::shared_ptr<int> p2(nullptr);    //传入空指针 nullptr
    
  • shared_ptr 模板还提供有相应的拷贝构造函数和移动构造函数,例如:

    std::shared_ptr<int> p3 = std::make_shared<int>(10);//同p3(new int(10))
    //调用拷贝构造函数
    std::shared_ptr<int> p4(p3);//或者 std::shared_ptr<int> p4 = p3;
    //调用移动构造函数
    std::shared_ptr<int> p5(std::move(p4)); //或者 std::shared_ptr<int> p5 = std::move(p4);
    
  • shared_ptr 只对它自身类型的指针包裹器(我们把这种智能指针称作指针包裹器吧)统计引用计数:

    int* ptr = new int;
    shared_ptr<int> p1(ptr);
    shared_ptr<int> p2(ptr);//错误用法
    shared_ptr<int> p3(ptr);//错误用法
    
  • unique_ptr

    表 4 unique_ptr指针可调用的成员函数
    成员函数名 功 能
    operator*() 获取当前 unique_ptr 指针指向的数据。
    operator->() 重载 -> 号,当智能指针指向的数据类型为自定义的结构体时,通过 -> 运算符可以获取其内部的指定成员。
    operator =() 重载了 = 赋值号,从而可以将 nullptr 或者一个右值 unique_ptr 指针直接赋值给当前同类型的 unique_ptr 指针。
    operator []() 重载了 [] 运算符,当 unique_ptr 指针指向一个数组时,可以直接通过 [] 获取指定下标位置处的数据。
    get() 获取当前 unique_ptr 指针内部包含的普通指针。
    get_deleter() 获取当前 unique_ptr 指针释放堆内存空间所用的规则。
    operator bool() unique_ptr 指针可直接作为 if 语句的判断条件,以判断该指针是否为空,如果为空,则为 false;反之为 true。
    release() 释放当前 unique_ptr 指针对所指堆内存的所有权,但该存储空间并不会被销毁。
    reset(p) 其中 p 表示一个普通指针,如果 p 为 nullptr,则当前 unique_ptr 也变成空指针;反之,则该函数会释放当前 unique_ptr 指针指向的堆内存(如果有),然后开始维护 p 所指堆内存。可以这样用:reset(new int)
    swap(x) 交换当前 unique_ptr 指针和同类型的 x 指针。
  • 基于 unique_ptr 类型指针不共享各自拥有的堆内存原则,因此 C++11 标准中的 unique_ptr 模板类没有提供拷贝构造函数,只提供了移动构造函数。例如

    std::unique_ptr<int> p4(new int);
    std::unique_ptr<int> p5(p4);//错误,堆内存不共享
    std::unique_ptr<int> p5(std::move(p4));//正确,调用移动构造函数
    
  • 释放规则

    //指定 default_delete 作为释放规则
    std::shared_ptr<int> p6(new int[10], std::default_delete<int[]>());
    //自定义释放规则
    void deleteInt(int*p) {
        delete []p;
    }
    //初始化智能指针,并自定义释放规则
    std::shared_ptr<int> p7(new int[10], deleteInt);
    
  • weak_ptr

    • weak_ptr是一种 辅助 shared_ptr 的指针
    • 比如用一个 shared_ptr 初始化 weak_ptr 后,
    • 该 shared_ptr 对象 reset() 自己后, 该对象.use_count() 永远返回零而不管实际的引用数如何
    • 因为她希望别人把她当做"指针"来对待而不是"对象" ,但该对象里面仍然有记录这实际的引用数的成员;
    • 仍然可以通过 weak_ptr 来访问到这个成员… … … 一个字: 离谱
      int* ptr = new int;
      shared_ptr<int> p3(ptr);
      shared_ptr p1(p3);
      shared_ptr p2(p1);
      weak_ptr wp(p1);// 注意  p1.reset(); 放在此句后面
      p1.reset();
      cout << boolalpha << endl;
      cout << wp.use_count() << endl;//2
      cout << p1.use_count() << endl;//0
      
    表 5 weak_ptr指针可调用的成员方法
    成员方法 功 能
    operator=() 重载 = 赋值运算符,是的 weak_ptr 指针可以直接被 weak_ptr 或者 shared_ptr 类型指针赋值。
    swap(x) 其中 x 表示一个同类型的 weak_ptr 类型指针,该函数可以互换 2 个同类型 weak_ptr 指针的内容。
    reset() 将当前 weak_ptr 指针置为空指针。
    use_count() 查看指向和当前 weak_ptr 指针相同的 shared_ptr 指针的数量。
    expired() 判断当前 weak_ptr 指针为否过期(指针为空,或者指向的智能指针记录的堆内存已经被释放)。
    lock() 如果当前 weak_ptr 已经过期,则该函数会返回一个空的 shared_ptr 指针;反之,该函数返回一个和当前 weak_ptr 指向相同的 shared_ptr 指针。(只是返回并不会增加引用计数)
    • weak_ptr 类型指针并不会影响所指 shared_ptr 内部统计的引用计数。
    • weak_ptr<T> 模板类没有重载 * 和 -> 运算符,因此 weak_ptr 类型指针只能访问某一 shared_ptr 指针指向的堆内存空间,无法对其进行修改。

三. 函数适配器

  • 函数符的概念:
    正如STL定义了容器和 iterator 的概念一样,它也定义了函数符(functor)的概念。
    生成器(generator)是不用参数就可以调用的函数符。
    一元函数(unary function)是用一个参数可以调用的函数符。
    二元函数(binary function)是用两个参数可以调用的函数符。
    例如,提供给for_each()的函数符应该是一元函数,因为它每次用于一个容器元素。当然,这些概念都有相应的改进版本:
    返回bool值的一元函数是谓词(predicate).
    返回bool值的二元函数是二元谓词(binary predicate).

    下面的代码删除容器中所有大于100的元素

    bool tooBig(int n){ return n > 100; }
    list<int> scores;
    ...
    scores.remove_if(tooBig);
    

    二元函数可用函数对象包裹成一元函数

    template<class T>
    class TooBig
    {
    private:
        T cutoff;
    public:
        TooBig(const T & t) : cutoff(t) {}
        bool operator()(const T & v) { return v > cutoff; }
    };
    
  • 自定义函数适配器

    //1、自定义unary_function
    //只要类继承了my_unary_function类,就可以被下面的AdaptorNot适配。
    template <typename arg, typename res>
    struct my_unary_function
    {
        typedef arg argument_type;
        typedef res result_type;//有这两个类型成员的称为自适应函数对象
    };
    template<class Arg, class Ret>
    class my_fun: public my_unary_function<Arg, Ret>
    {
        my_fun() {};
        Ret operator()(Arg arg)
        {
            Ret mybool;
            //do something
            return mybool;
        }
    
    };
    //2、改写带模板的函数适配器
    template <typename T>
    class AdaptorNot
    {
    protected:
        T opt;
    
    public:
        AdaptorNot(T x) : opt(x) {}
        //重载了括号
        typename T::result_type operator()(typename T::argument_type flag)
        {
    	typename T::result_type ret;
    	//do something
            return !opt(flag);
        }
    };
    

四. STL容器

Sequence containers:

1. array

  • 和其它容器不同,array 容器的大小是固定的

  • array<T,N> 类模板中,T 用于指明容器中的存储的具体数据类型,N 用于指明容器的大小,需要注意的是,这里的 N 必须是编译时能确定的常量,不能用变量表示。

    std::array<double, 10> values {0.5,1.0,1.5,,2.0};
    

    这里只初始化了前 4 个元素,剩余的元素都会被初始化为 0.0。

  • 当两个 array 容器满足大小相同并且保存元素的类型相同时,两个 array 容器可以直接直接做赋值操作,即将一个容器中的元素赋值给另一个容器。

  • 在满足以上 2 个条件的基础上,如果其保存的元素也支持比较运算符,就可以用任何比较运算符直接比较两个 array 容器。

    表 6 array容器成员函数汇总
    成员函数 功能
    begin() 返回指向容器中第一个元素的随机访问迭代器。
    end() 返回指向容器最后一个元素之后一个位置的随机访问迭代器,通常和 begin() 结合使用。
    rbegin() 返回指向最后一个元素的随机访问迭代器。
    rend() 返回指向第一个元素之前一个位置的随机访问迭代器。
    cbegin() 和 begin() 功能相同,只不过在其基础上增加了 const 属性,不能用于修改元素。
    cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crbegin() 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    size() 返回容器中当前元素的数量,其值始终等于初始化 array 类的第二个模板参数 N。
    max_size() 返回容器可容纳元素的最大数量,其值始终等于初始化 array 类的第二个模板参数 N。
    empty() 判断容器是否为空,和通过 size()==0 的判断条件功能相同,但其效率可能更快。
    at(n) 返回容器中 n 位置处元素的引用,该函数自动检查 n 是否在有效的范围内,如果不是则抛出 out_of_range 异常。
    front() 返回容器中第一个元素的直接引用,该函数不适用于空的 array 容器。
    back() 返回容器中最后一个元素的直接应用,该函数同样不适用于空的 array 容器。
    data() 返回一个指向容器首个元素的指针。利用该指针,可实现复制容器中所有元素等类似功能。
    fill(val) 将 val 这个值赋值给容器中的每个元素。
    array1.swap(array2) 交换 array1 和 array2 容器中的所有元素,但前提是它们具有相同的长度和类型。

2. vector

  • vector 常被称为向量容器,因为该容器擅长在尾部插入或删除元素,在常量时间内就可以完成,时间复杂度为O(1);而对于在容器头部或者中部插入或删除元素,则花费时间要长一些(移动元素需要耗费时间),时间复杂度为线性阶O(n)。<< 大O表示法 >>
  • 初始化vector
    std::vector<double> values(20);//values 容器开始时就有 20 个元素,它们的默认初始值都为 0。
    std::vector<double> values(20, 1.0);//第二个参数指定了所有元素的初始值,因此这 20 个元素的值都是 1.0。
    int num=20;
    double value =1.0;
    std::vector<double> values(num, value);
    std::vector<char>value1(5, 'c');
    std::vector<char>value2(value1);
    int arr[]={1,2,3};
    std::vector<int>values(arr, arr+2);//values 将保存{1,2}
    std::vector<int>value1{1,2,3,4,5};
    std::vector<int>value2(std::begin(value1),std::begin(value1)+3);//value2保存{1,2,3}
    
    表 7 vector 容器的成员函数
    函数成员 函数功能
    begin() 返回指向容器中第一个元素的迭代器。
    end() 返回指向容器最后一个元素所在位置后一个位置的迭代器,通常和 begin() 结合使用。
    rbegin() 返回指向最后一个元素的迭代器。
    rend() 返回指向第一个元素所在位置前一个位置的迭代器。
    cbegin() 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crbegin() 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    size() 返回实际元素个数。
    max_size() 返回元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。
    resize() 改变实际元素的个数。
    capacity() 返回当前容量。
    empty() 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
    reserve() 增加容器的容量。
    shrink _to_fit() 将内存减少到等于当前元素实际所使用的大小。
    operator[ ] 重载了 [ ] 运算符,可以向访问数组中元素那样,通过下标即可访问甚至修改 vector 容器中的元素。
    at() 使用经过边界检查的索引访问元素。
    front() 返回第一个元素的引用。
    back() 返回最后一个元素的引用。
    data() 返回指向容器中第一个元素的指针。
    assign() 用新元素替换原有内容。
    push_back() 在序列的尾部添加一个元素。
    pop_back() 移出序列尾部的元素。
    insert() 在指定的位置插入一个或多个元素。
    erase() 移出一个元素或一段元素。
    clear() 移出所有的元素,容器大小变为 0。
    swap() 交换两个容器的所有元素。
    emplace() 在指定的位置直接生成一个元素。
    emplace_back() 在序列尾部生成一个元素。
  • 还需注意的是,如果调用 reserve() 来增加容器容量,之前创建好的任何迭代器(例如开始迭代器和结束迭代器)都可能会失效,这是因为,为了增加容器的容量,vector<T> 容器的元素可能已经被复制或移到了新的内存地址。所以后续再使用这些迭代器时,最好重新生成一下。

3. deque

  • 双端队列, 如其名, 头部和尾部都能添加元素; 那么如何管理给元素分配的内存并能合理的增删改查呢 ?
    • 1.在堆上分配size大小的指针数组, 记录该数组头和尾和的地址b e,并记录元素的beg end cur位置, 在size/2的位置 开始添加元素. 这样,尽管给元素分配的内存都不连续(数组中每个指针指向的内存), 但这些指针变量本身的地址却记录在序列的数组内. 这样就足以增删改查
      • 如果beg==b, 或 end==e ,那么就需要重新分配更大的指针数组, 并把新的指针数组内的各个指针指向原来的指针数组内的各个指针指向的内存. 元素数据没变, 包裹着元素的容器却变了
    • 2.使用链表, 双向链表. 使用链表总是能使大数量的数据能够形成逻辑上自洽的树,网,链,环等结构
  • 与vector 相比, 添加了在前端增加元素的front相关的方法, 删除了capacity()、reserve() 和 data() 成员函数。
    • 这就意味着 deque 容器几乎完全自行管理内存
  • 双端队列都不能保证存储其所有要素在连续的储存地点
  • 涉及频繁插入或清除元素操作时可选用 deque 容器

4. list

  • 内部使用双向链表来存储数据
  • 表 8 list 容器可用的成员函数
    成员函数 功能
    begin() 返回指向容器中第一个元素的双向迭代器。
    end() 返回指向容器中最后一个元素所在位置的下一个位置的双向迭代器。
    rbegin() 返回指向最后一个元素的反向双向迭代器。
    rend() 返回指向第一个元素所在位置前一个位置的反向双向迭代器。
    cbegin() 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crbegin()  和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改元素。
    empty() 判断容器中是否有元素,若无元素,则返回 true;反之,返回 false。
    size() 返回当前容器实际包含的元素个数。
    max_size() 返回容器所能包含元素个数的最大值。这通常是一个很大的值,一般是 232-1,所以我们很少会用到这个函数。
    front() 返回第一个元素的引用。
    back() 返回最后一个元素的引用。
    assign() 用新元素替换容器中原有内容。
    emplace_front() 在容器头部生成一个元素。该函数和 push_front() 的功能相同,但效率更高。
    push_front() 在容器头部插入一个元素。
    pop_front() 删除容器头部的一个元素。
    emplace_back() 在容器尾部直接生成一个元素。该函数和 push_back() 的功能相同,但效率更高。
    push_back() 在容器尾部插入一个元素。
    pop_back() 删除容器尾部的一个元素。
    emplace() 在容器中的指定位置插入元素。该函数和 insert() 功能相同,但效率更高。
    insert()  在容器中的指定位置插入元素。
    erase() 删除容器中一个或某区域内的元素。
    swap() 交换两个容器中的元素,必须保证这两个容器中存储的元素类型是相同的。
    resize() 调整容器的大小。
    clear() 删除容器存储的所有元素。
    splice() 将一个 list 容器中的元素插入到另一个容器的指定位置。
    remove(val) 删除容器中所有等于 val 的元素。
    remove_if() 删除容器中满足条件的元素。
    unique() 删除容器中相邻的重复元素,只保留一个。
    merge() 合并两个事先已排好序的 list 容器,并且合并之后的 list 容器依然是有序的。
    sort() 通过更改容器中元素的位置,将它们进行排序。
    reverse() 反转容器中元素的顺序。
  • 初始化如同 vector 的初始化方式

5. forward_list

  • 内部使用单向链表来存储数据
  • 步进还可以使用advance();
  • distance(),传入两个迭代器, 计算它们之间的元素个数;

Associative containers:

  • 和序列式容器不同的是,关联式容器在存储元素时还会为每个元素在配备一个键,整体以键值对的方式存储到容器中。相比前者,关联式容器可以通过键值直接找到对应的元素,而无需遍历整个容器。另外,关联式容器在存储元素,默认会根据各元素键值的大小做升序排序。
    相比其它类型容器,关联式容器查找、访问、插入和删除指定元素的效率更高

1. map

  • pair: 单个键值对容器 在#include <utility>中定义

    pair kl("hello", 20);
    
  • map: 多个键值对容器, 并且能指定排序规则

  • 使用 map 容器存储的各个键值对,键的值既不能重复也不能被修改。
    map 模板头:

    template <typename _Key, typename _Tp, typename _Compare = std::less<_Key>,
        typename _Alloc = std::allocator<std::pair<const _Key, _Tp> > >
      class map {...}
    

    第三个参数是排序规则 默认是 std::less<_Key> 升序 一般是依据键 来排序
    初始化:

    std::map<std::string, int>myMap{ {"some c++ things", 10}, {"python things", 20} };
    std::map newMap(++myMap.begin(), myMap.end());
    cout << newMap.begin()->first << endl; //some c++ things
    
    表 9 C++ map容器常用成员方法
    成员方法 功能
    begin() 返回指向容器中第一个(注意,是已排好序的第一个)键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
    end() 返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
    rbegin() 返回指向最后一个(注意,是已排好序的最后一个)元素的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
    rend() 返回指向第一个(注意,是已排好序的第一个)元素所在位置前一个位置的反向双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的反向双向迭代器。
    cbegin() 和 begin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
    cend() 和 end() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
    crbegin() 和 rbegin() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
    crend() 和 rend() 功能相同,只不过在其基础上,增加了 const 属性,不能用于修改容器内存储的键值对。
    find(key) 在 map 容器中查找键为 key 的键值对,如果成功找到,则返回指向该键值对的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
    lower_bound(key) 返回一个指向当前 map 容器中第一个 >= key 的键值对的双向迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
    upper_bound(key) 返回一个指向当前 map 容器中第一个 > key 的键值对的迭代器。如果 map 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
    equal_range(key) 该方法返回一个包含 2 个双向迭代器 pair 对象,其中 pair.first 和 lower_bound() 方法的返回值等价,pair.second 和 upper_bound() 方法的返回值等价。也就是说,该方法将返回一个范围,该范围中包含的键为 key 的键值对(map 容器键值对唯一,因此该范围最多包含一个键值对)。
    empty()  若容器为空,则返回 true;否则 false。
    size() 返回当前 map 容器中存有键值对的个数。
    max_size() 返回 map 容器所能容纳键值对的最大个数,不同的操作系统,其返回值亦不相同。
    operator[] map容器重载了 [] 运算符,只要知道 map 容器中某个键值对的键的值的引用,就可以向获取数组中元素那样,通过键直接获取对应的值。如果容器中没有这个键,就增加这个键,其值:基本数据类型,则值为 0;如果是 string 类型,其值为 "",即空字符串
    at(key) 找到 map 容器中 key 键对应的值,如果找不到,该函数会引发 out_of_range 异常。
    insert() 向 map 容器中插入键值对。
    erase() 删除 map 容器指定位置、指定键(key)值或者指定区域内的键值对。后续章节还会对该方法做重点讲解。
    swap() 交换 2 个 map 容器中存储的键值对,这意味着,操作的 2 个键值对的类型必须相同。
    clear() 清空 map 容器中所有的键值对,即使 map 容器的 size() 为 0。
    emplace() 在当前 map 容器中的指定位置处构造新键值对。其效果和插入键值对一样,但效率更高。
    emplace_hint() 在本质上和 emplace() 在 map 容器中构造新键值对的方式是一样的,不同之处在于,使用者必须为该方法提供一个指示键值对生成位置的迭代器,并作为该方法的第一个参数。
    count(key) 在当前 map 容器中,查找键为 key 的键值对的个数并返回。注意,由于 map 容器中各键值对的键的值是唯一的,因此该函数的返回值最大为 1。
  • equal_range(key) 用法示例:

    #include <iostream>
    #include <utility>  //pair
    #include <map>      // map
    #include <string>       // string
    using namespace std;
    int main() {
        //创建并初始化 map 容器
        std::map<string, string>myMap{ {"STL教程","http://c.biancheng.net/stl/"},
                                       {"C语言教程","http://c.biancheng.net/c/"},
                                       {"Java教程","http://c.biancheng.net/java/"} };
        //创建一个 pair 对象,来接收 equal_range() 的返回值
        pair <std::map<string, string>::iterator, std::map<string, string>::iterator> myPair = myMap.equal_range("C语言教程");
        //通过遍历,输出 myPair 指定范围内的键值对
        for (auto iter = myPair.first; iter != myPair.second; ++iter) {
            cout << iter->first << " " << iter->second << endl;
        }
        return 0;
    }
    

    和 lower_bound(key)、upper_bound(key) 一样,该方法也更常用于 multimap 容器,因为 map 容器中各键值对的键的值都是唯一的,因此通过 map 容器调用此方法,其返回的范围内最多也只有 1 个键值对。

    用[]修改pair 中的 second:

    #include <iostream>
    #include <map>      // map
    #include <string>   // string
    using namespace std;
    int main() {
        //创建空 map 容器
        std::map<string, string>myMap;
        myMap["STL教程"]="http://goodstl/somthingelse/";
        myMap["Python教程"] = "http://goodcode/python/";
        myMap["STL教程"] = "http://goodstl/stl/";//假设没有"STL教程"这个键的话,那么这就是添加操作
        for (auto i = myMap.begin(); i != myMap.end(); ++i) {
            cout << i->first << " " << i->second << endl;
        }
        return 0;
    }
    

    insert() 插入键值对; 也能以初始化列表的方式传入

    • 当该方法将键值对成功插入到 map 容器中时,其返回的迭代器指向该新插入的键值对,同时 bool 变量的值为 true;
    • 当插入失败时,则表明 map 容器中存在具有相同键的键值对,此时返回的迭代器指向此具有相同键的键值对,同时 bool 变量的值为 false。
    std::map<string, string>myMap;
    pair p{"somekey", "somevalue"};
    auto ret = myMap.insert(p);//返回 std::pair<iterator, bool> 类型
    cout << ret.second << endl;
    cout << ret.first->first <<" "<<ret.first->second<< endl;
    

    emplace() 或者 emplace_hint() 效率比 insert() 高;可直接用键,值 来传参

    mymap.emplace("someKey", "http://c.someValue.net/");
    

    注意: 可以用初始化列表初始化 但不能使用 pair 类型初始化

    multimap<string, string>mymultimap{pair("zhello", "world")};
    map<string, string>mymap{pair("zhello", "world")};
    map<string, string>mymap(pair("zhello", "world"));//error
    //这就意味着没有重载pair类型版本的构造函数, 而是在初始化列表版本的构造函数里对pair类型做处理
    

2. multimap

  • 和 map 容器的区别在于,multimap 容器中可以同时存储多(≥2)个键相同的键值对。(值也可以相同)
  • emplace() 返回该标识该键值对的迭代器

3. set

  • 成员方法类似map容器, 但键和值都归为同一个值,同一类型 合体了属于是. 下面是定义:
    template<typename _Key, typename _Compare = std::less<_Key>,
       typename _Alloc = std::allocator<_Key> >
    class set
    {
    ...
      typedef _Key     key_type;
      typedef _Key     value_type;
    ...
    }
    
  • set 容器存储的元素必须互不相等。

4. multiset

  • multiset 容器可以存储多个相同的元素。

5. 自定义排序规则

  • 先看看冒泡排序:
    int sortNum[] {1, 8, 5, 4, 3};
    auto sortNumSize = end(sortNum) - begin(sortNum);
    for (int i = sortNumSize - 1; i >= 0; i--)
    {
        for (int j = i; j >= 0 ; --j)
        {
            if (sortNum[i] < sortNum[j]) //为true时交换
            {
                //交换a与b的位置
                auto temp = sortNum[i];
                sortNum[i] = sortNum[j];
                sortNum[j] = temp;
            }
        }
    }
    for (int i = 0; i < sortNumSize; i++)
    {
        cout << sortNum[i] << "," ;
    }
    
    为true时交换, 从代码上看, 如果是sortNum[i] < sortNum[j]则是升序, 而如果是sortNum[i] > sortNum[j]则是降序. 完全可以把这部分代码独立出去 作为排序规则;
    你来指定规则, 而我按你的规则为true时来排序,参见<<三. 函数适配器>>这就是STL容器排序和排序规则分离的大概实现思路.

Unordered associative containers:

  • 无序关联式容器,又称哈希容器。和关联式容器一样,此类容器存储的也是键值对元素;不同之处在于,关联式容器默认情况下会对存储的元素做升序排序,而无序关联式容器不会。
  • set容器的底层实现是红黑树, 而所有无序容器的底层实现都采用的是哈希表存储结构。
OWASP-ZAP扫描器的使用 目录 OWASP-ZAP 更新 代理 目录扫描 主动扫描(Active Scan) 扫描结果 生成报告 OWASP-ZAP OWASP Zed攻击代理(ZAP)是世界上最受欢迎的免费安全审计工具之一,由数百名国际志愿者积极维护。它可以帮助你在开发和测试应用程序时自动查找Web应用程序中的安全漏洞。 也可以说ZAP是一个中间人代理。它能够获取你对Web应用程序发出的所有请求以... 阅读详情

相关推荐

非华为电脑也能用!华为电脑管家完美安装教程来了

GitHub 上有一个开源项目 ​****​,专门解决“非华为设备无法安装华为电脑管家”的问题。它通过智能模拟 + DLL 劫持技术,绕过官方对硬件型号的检测,让你在联想、戴尔、华硕甚至 DIY 主机上也能流畅使用华为电脑管家!⭐ 项目已获 ​700+ Stars​,社区活跃,持续更新,兼容性优秀!科技不该有围墙。如果你成功在非华为电脑上跑起了 PCManager,欢迎在评论区晒出你的设备型号 + 使用体验!也别忘了把这篇推文分享给同样“眼馋”华为生态的朋友 ~📱 ​关注我们。

程序员朱永胜 4909

STL简介以及string 类

STL 什么是STL STL(standard template libaray-标准模板库):是C++标准库的重要组成部分,不仅是一个可复用的组件库,而且是一个包罗数据结构与算法的软件框架。 通俗上来讲,STL就是将常见的数据结构以模板的方式进行封装,包含常见的泛型算法。 常见的数据结构:顺序表、链表、队列、栈、堆、二叉树、哈希表 STL的六大组件 a.容器 容器是存储其他对象(其元素)集合的容器对象。它们是作为类模板实现的,这使得作为元素支持的类型具有很大的灵活性。 容器管理其元素的存储

m0_56910081的博客 1001

在x86机器上运行jailhouse

jailhouse jaihouse提供了一个demo ,https://github.com/siemens/jailhouse-images可以用于编译一整套可用的demo。 适用于多个平台。编译过程主要参考https://blog.youkuaiyun.com/weixin_39541632/article/details/110422345 此demo可以生成多个平台所用的操作系统image。 ...

闲人的专栏 3004

STL —— string

1.什么是STL:   STL = Standard Template Library,标准模板库,惠普实验室开发的一系列软件的统称。它是由Alexander Stepanov、Meng Lee和David R Musser在惠普实验室工作时所开发出来的。这可能是一个历史上最令人兴奋的工具的最无聊的术语。从根本上说,STL是一些“容器”的集合,这些“容器”有list,vector,set,map

凨 919

DETRs with Collaborative Hybrid Assignments Training论文阅读与代码

在这篇论文中,作者观察到在DETR中将过少的 Query 分配为正样本,采用一对一的集合匹配,会导致对编码器输出的监督稀疏,严重损害编码器的区分特征学习,反之亦然,也会影响解码器中的注意力学习。为了缓解这个问题,作者提出了一种新颖的协同混合分配训练方案,名为Co-DETR,以从多样的标签分配方式中学习更高效、更有效的基于DETR的检测器。这种新的训练方案可以通过训练多个并行辅助 Head ,以一对多的标签分配方式(如ATSS和Faster RCNN)进行监督,轻松增强端到端检测器中编码器的学习能力。

qingjing0413的博客 1153

【NodeRed】node-red-contrib-opcua实现PLC读写

在之前的博文【Node-RED】node-red-contrib-opcua-server模块使用(1)中,我们介绍了用node-red-contrib-opcua-server模块实现OPCUA服务端的,以及二次开发的内容。本节博文中我们采用官方社区自带的node-red-contrib-opcua组件开展对OPCUA客户端的介绍,详细阐述用该组件中OpcUa-Client节点实现客户端对PLC的读写,以及实现过程中遇到的问题。由于官方社区中并没有找到该组件的介绍实例,这也是本博文编写的第1个原因。

weixin_48618536的博客 957

(C++学习笔记十四)STL(Standard Template Library) 之vector 容器

十六.STL 之 string 容器 代码片内有详解 : 1.Code : #include<iostream> using namespace std; #include<string> //Standard Teplate Library 的常用容器 // string 容器 //概念: string 是C++ 风格的字符串, 而其本质是一个 类 // // 一. string 构造函数 //string(); //创建一个空的字符串 例如: string

qq_37459242的博客 258

uniapp - 最新微信小程序手机号一键登录功能效果,uniapp小程序实现手机号码一键登录,uniapp微信小程序端通过手机号授权完成立即登录操作(详细示例源码,新手小白一键复制开箱即用)

uniapp,微信小程序,uniapp小程序平台,uniApp手机号一键登录,uniapp小程序端手机号一键登录功能,实现微信小程序手机号一键登录,在uniapp中实现获取手机一键登录功能,uniapp手机号快捷登录,uniapp微信小程序授权登录并获取手机号,微信小程序手机号快速验证组件调用方式,uniapp小程序怎么用手机号一键登录,uniapp一键登录流程及代码,如何获取手机号一键登录到小程序,微信小程序获取本机手机号一键登录功能,新手详细教程,详细手机一键登录完整示例代码,uni-app微信unia

✅ 精选推荐文章 1万+

c++蓝桥4 STL

STL 头文件 为了避免和其他头文件冲突, STL的头文件不再使用常规的.h扩展。为了包含标准的string类,迭代器和算法,用下面的指示符: #include &lt;string&gt; #include &lt;iterator&gt; #include &lt;algorithm&gt; 收藏 https://blog.youkuaiyun.com/fu_zk/article/detail...

Christy小小的博客 194

Agentic AI应用架构师如何提升AI应用的灵活性

可扩展性(Scalability):快速添加新功能或扩展任务范围(如Agent从“客服”扩展到“供应链管理”);可修改性(Modifiability):调整Agent的决策逻辑或动作策略,无需重构整个系统;鲁棒性(Robustness):在环境异常或数据噪声下保持性能稳定;自适应(Self-Adaptation):自主学习新场景,无需人工干预。状态空间(S):Agent能感知的所有内部/外部状态(如用户需求、环境数据);动作空间(A):Agent能执行的所有动作(如调用工具、发送消息);

项目管理的博客 578

基于环形槽谐振器与PIN二极管的频率可重构Vivaldi天线设计与CST仿真研究

摘要 本文设计了一种基于FR4基板的频率可重构Vivaldi天线,通过集成环形槽谐振器(CSRR)和PIN二极管开关实现超宽带(UWB,2-8 GHz)与窄带(2.4/3.5/5.2 GHz)模式的电控切换。天线采用指数渐变槽线结构,结合CSRR的滤波特性和PIN二极管的开关功能,利用CST仿真优化参数。结果表明,UWB模式下S11<-10 dB,窄带模式下目标频点谐振显著,其他频段抑制良好,验证了设计的可行性。该方案为多频段无线通信系统提供了紧凑、低成本的可重构天线解决方案。 关键词:频率可重构天线

huanghm88的专栏 217

C++学习日记--STL vector、string容器

一、STL。 1、STL诞生。 长久以来,软件界一直希望能够建立一种可重复利用的东西。 C++的面向对象和泛型编程思想,目的就是复用性的提升。 大多数情况下,数据结构和算法都未能有一套标准,导致被迫做大量重复的工作。 为了建立数据结构和算法一套标准,诞生了STL。 2、STL基本概念。 STL(Standard Template Library) -> 标准模板库 STL分为:容器(container)、算法(algorithm)、迭代器(iterator) 容器与算法之间通过迭代器进行无缝连接。.

KLh 322

Python白色飘雪(完整代码)

Python绘制白色飘雪动画的完整代码。

AIGC 3万+

STL基本概念,三大组件基本使用,string容器

STL(Standard Template Library)标准模板库 STC从广义上分为:容器,算法(algorithm),迭代器。容器和算法之间通过迭代器进行无缝连接 一句话STL牛皮,大兄弟。 第一种遍历: 先可以将迭代器理解成指针 #include<iostream> #include<vector> using namespace std; void ...

weixin_43767691的博客 255

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

C++教程 | STL编程 | 常用函数操作手册 | Vector容器和String容器

目录STL基本概念Vector容器vector容器的基本概念vector容器的初始化vector容器的容量和大小Vector容器的插入和删除vector数据存取vector互换容器vector预留空间存放自定义的数据类型容器嵌套容器String容器string初始化string的赋值操作string字符串的拼接string字符串的查找和替换string字符串的比较string字符串的遍历和修改string字符串的插入和删除截取子串 STL基本概念 STL的诞生 1.长久以来,软件界一直希望建立一种可重复利

lijiamingccc的博客 1757

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

STL库中string类内存布局的探究

在STL中有着一个类就是string类,他的内存布局和存储机制究竟是怎么样的呢? 这就是建立好的string 可以看出,图中用黄色框框标注的部分就是主要区域 我们用来给string对象进行初始化的字符串被存储在了_Buf当中,_Mysize和_Myres就不用说了,就是上面的size 和 capacity 的值。 当只有一个字符作为字符串的时候,就可以很明显的看出来了,_Mysize是指字符串的length _Myres还是没有改变,_Myres最大就是15么? 此时还没有变化,再加

danshiming的博客 299

精雕软件(JDpaint) 5.5 绿色版

精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版精雕软件(JDpaint) 5.5 绿色版

C++——STL容器(string容器、vector容器)

STL基本概念: STL从广义上分:容器,算法,迭代器; 容器和算法之间通过迭代器进行无缝对接; STL几乎所有的代码都采用了模板类或模板函数; STL六大组件: 容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器; 1.容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据; 2.算法:各种常用算法,如sort、find、copy、for_each等; 3.迭代器:扮演了容器与算法之间的胶合剂; 4.仿函数:行为类似函数,可作为算法的某种策略; 5.适配器:一种用来

没实力的码农写的渣渣博客 332

STL基础知识

STL简介和string类

eptcup_的博客 244

【C++】模板、STL、浅拷贝和深拷贝、string类模拟实现

泛型编程:编写与类型无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。 函数模板:函数模板代表了一个函数家族,该函数模板与类型无关,在使用时被参数化,根据实参类型产生函数的特定类型版本。 函数模板格式: template 返回类型值 函数名(参数列表){} 函数模板的实例化 隐式实例化和显示实例化 一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数 对于非模板函数和同名函数模板,...

mjy5201的博客 313

STL概述

string 类: [] 和 at 锁定指定字符的区别 find() 查找 replace() 替换 compare() 比较 substr() 剪切 insert() 插入 erase() 删除 将string类型转换为const char * 使用 c_str() 函数,char *类型可以隐式转换为string类型,反之不可以隐式转换 toupper(字符) ...

清浅 267

总结笔记3.20

一.万能头文件 include<bits/stdc++.h> sync_with_stdio(false) 加快程序运行速度 srand(time(0)); rand()%10; 生成随机数 二.stack 1.定义:stack<typename>name; 2.stack容器内元素的访问 由于栈(stack)本身是一种后进先出的数据结构,在STL的stack只能通过top()来访问栈顶元素。 3.操作 (1)push() push(x)将x入栈。 (2)top...

m0_66484415的博客 288

讲座笔记(乱糟糟版)

暂且学完了STL中的string,很好用! 我想好好学!!!希望先不要被淘汰,再给我一点时间。 讲座上的小老师们都很好! #include<bits/stdc++.h> using namespace std; //#include <string.h> #include<iostream> int kkk(string str){ if(str=="one")return 1;//strcmp(str1,str2),str.compare(s1) else if(

qq_51070956的博客 528

C++ Standard Template Library

1.Vector 1.1 definition 变长数组 //一维变长数组 vector <typename> name //二维变长数组 vector <typename> name[ArraySize] 1.2 vector元素的访问 通过下标访问 通过迭代器访问 iterator的定义是,类似指针的东西 vector <typename> :: it...

qq_44761480的博客 1183

STL常用容器-string容器

/ 从右往左查找str最后一次出现的位置,从pos位置开始查找,pos默认值是npos,npos是string类的静态常量,值是-1,表示字符串结束;// pos是position位置,代表从0开始的下标,从pos位置开始,将s字符串后面的n个字符拼接到当前的字符串后面;//把字符串s的前n个字符赋给当前的字符串;

m0_74380601的博客 1068

C++ STL(Standard Template Library)学习汇总

STL的可读性极佳,运用极广,被选为GNU C++的标准程序库,又开放自由运用。不仅最为人广泛运用的各种数据结构和算法在STL中有良好的实现,连内存配置与管理也都重重考虑了最佳效能。一切的一切,除了实现软件积木的高度复用性,让各种组件得以灵活搭配运用,更考虑了实现上的关键议题:效率

李思成的博客 473

STL(standard template library)标准模板库(一)

使用前,要包括#include<set>头文件,set在插入后会自动排序,并且去重,multiset可以插入重复数据,也可以排序。在不溢出的情况下,在vector<int> s和vector<int> s(3)的情况下,可以正常输出(与一般数组使用无异)s.capacity()是指开辟的s的数组的容量,s.size()是指函数中使用的长度。(知道数组多长),以创建int类型,数组长度为3为例,vector<int> s(3);(不知道数组多长) ,以创建int类型s数组为例,vector<int> s;

zhangguojia7的博客 1134
上一篇: Modeless dialog in html
下一篇: std::declval 元函数
Computer_Tech
博客等级 码龄3年 573粉丝 49原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值