day10c++

一.可变参数

1.1C语言的可变参数

实现原理:参数个数不确定,但是所有参数保存在栈上是连续的

实现可变参数的条件:函数的参数一定要有特殊的作用(标明后面参数的个数或者类型)

#include <iostream>
#include <stdarg.h>
using namespace std;
int func(int num1,int num2,...)
{
    va_list v1;
    va_start(v1,num1);
    printf("v1 = %d\n",*v1);
    int res;
    printf("res = %d\n",res);
    for(int i = 0;i < num1;i++)
    {
        res = va_arg(v1,int);
        printf("res = %d\n",res);
    }
    va_end(v1);
    return 0;
}
int main(int argc, const char *argv[])
{
    func(3,5,6,7);
    return 0;
}
1.2c++中的可变参数

不建议使用C语言的可变参数,因为内部原型检查机制不全,不安全

initialize_list 列表初始化

1.3initialize_list 列表初始化

1.3.1本质

用于表示某种特定类型的值的数组,和vector一样,initialize_list也是一种模板类型

1.3.2使用

用{}来初始化变量,比如:std::vector<int> a{1,2,3,4,5};

1.3.3初始化区别

int c = 3.3       / /默认类型转换

int b = (int){3.3}  /  / 编译器会发出警告(也有可能是错误)

1.3.4使用#include <iostream>
#include <stdarg.h>
using namespace std;
class A
{
    public:
        A(const initializer_list<int> &t)
        {
            for(auto tmp : t)
            {
                cout << tmp << endl;
            }
        }
};
template <typename T>
void func(initializer_list<T> arg)
{
    auto it = arg.begin();
    for(;it != arg.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
int main(int argc, const char *argv[])
{
    initializer_list<int> init_list{1,2,3,4,5,6};
    auto it = init_list.begin();
    for(;it != init_list.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    
    initializer_list<int> arg{1,2,3,4,5,6};
    func(arg);
    A a(arg);
    return 0;
}
 三STL

3.1STL的概念

为了复用性的提升,为了建立数据结构和算法的一套标准,并且降低其间的耦合关系,以及提升各自的独立性(高内聚),交互性操作(相互合作性),c++社群诞生了STL

3.2价值

低层次:一个非常实用的零部件,以及以一个整合的组织去使用

高层次:以泛型思维为基础,系统化,条例清晰的:“软件组织分类学”。

3.3历史

STL  1979 c++ 1971年
1987年 Ada libray c++还未提出template
1992 帕罗奥图 Alex项目-->Stl
1993年 贝尔 ANSI/ISOC++

3.4STL的六大组件

(1)容器

各种数据结构:vector,list,deque,set,map,用来存放数据

从实现角度看:是一种类模板,就体积而言,占总85%以上

(2)算法

各种常用的算法:sort,seach,copy,erase...

从实现角度看:function template

(3)迭代器(实现重载)

容器和算法之间的胶合剂,又称为“泛型指针”,以及其他衍生的变化

从实现角度看:重载operator*,operator->,operator++,operator--等指针相关操作(class Template)

所有的STL都附带有自己的专属迭代器

(4)仿函数

行为类似函数,内部重载了()的类或者类模板,一般的函数指针可以狭义的理解为仿函数

(5)配置器(配接器)

一种修饰容器或仿函数或迭代器接口的东西,例如:STL提供的stack和queue,虽然看似是容器,其实只能算是一种容器配接器,因为他们底层完全借助于deque,所有的操作都由deque供应

改变functor接口者,称为function adapter(bind,negate(否定),compose(组合))

改变container接口者,称为container adapter

改变iterator接口者,称为iterator adapter

(6)空间适配器

负责空间置配与管理(内存池计数)

从实现角度看:配置器实现了一个动态空间置配,空间管理,空间释放(class Template)

SGI STL 第一级置配器 > 128byte

SGI STL 第二级置配器 16个自由链表(8 16 24 32 40 48 56 64 72 80 96 104 112 120 128)

3.5容器

3.5.1容器分类

序列式容器(顺序容器):array(c++内建),vector,list,heap,priority-heap,slist,deque,stack,queue

forward_list(c++11)

关联式容器:RB-tree(非公开) set  map  multiset  multimap   hashtable   hash-set   hash-map

3.5.2确定使用哪种容器

通常,vector是最好的选择,除非你有更好的理由选择其他容器

1.如果你的程序有很多小的元素,且空间的额外开销很重要,则不要使用list或forward_list

2.如果程序要求随机访问元素,应该使用vector或者deque

3.如果想在容器的中间插入或者删除元素,则list或forward_list应该是首选

4.如果程序要在头尾位置插入或者删除元素,但是不会在中间为hi插入或删除元素,则使用deque

5.如果想在程序中随机访问元素,又要在容器的中间插入元素,该怎么办?

------->答案取决于list或者forward_list中访问元素与vector或deque中插入,删除元素的相对性能。

    一般来说,应用中占主导地位的操作决定了容器类型的选择

6.如果你还是不确定应该使用哪种容器,那么可以只是用vector或者list公共的操作:使用公共的操作:迭代器

不使用下标操作,避免随机访问,这样使用两者,都比较方便

3.5.3vector容器的内存如何增长

3.5.4vector的数据结构

template <class T,class Alloc = alloc>

class Vector

{

protected:

        iterator start;    //表示目前使用空间的头

        iterator finish;   //表示目前使用空间的尾

         iterator end_of_storage  //表示目前可用空间的尾

};

 

vector中push_back和emplace_back的区别:push_back插入一次调用一次析构函数,emplace_back是全部插入之后一起调用析构函数,效率更高

#include <iostream>
#include <vector>
#include <list>
using namespace std;
class Test
{
    public:
        int m_a;
        int m_b;
    public:
        Test()
        {
            cout << "Test" << endl;
        }
        Test(int a):m_a(a)
        {
            cout << m_a << "Test's create with one num" << endl;
        }
        Test(const Test &obj)
        {
            cout << "Test's copy create" << endl;
            this->m_a = obj.m_a;
            this->m_b = obj.m_b;
        }
        ~Test()
        {
            cout << "~Test" << endl;
        }
};
ostream &operator<<(ostream &out,const Test &obj)
{
    out << obj.m_a << endl;
    return out;
}
int main(int argc, const char *argv[])
{
    vector<int> v1;
    vector<string> vs;
    vector<vector<string>> vv;
    vector<Test> v3;
    vector<int> v4 = {1,2,3,4,5,6};
    vector<int> v5(v4);
    vector<int> v6(v4.begin()+1,v4.end());
    vector<int> v7(100);
    vector<string> v8 = {10,"hello"};
    vector<int> v9(100,5);

    v3.reserve(10);
    cout << v3.capacity() << endl;
    v3.push_back(Test(1));
    v3.push_back(Test(2));
    v3.push_back(Test(3));
    v3.insert(v3.end(),Test(4));


    v3.emplace_back(1);
    v3.emplace_back(2);
    v3.emplace_back(3);
    cout << v3.capacity() << endl;
    v3.emplace(v3.begin()+1,Test(5));
    v3.resize(10);
    v3.resize(10,9);
    cout << v3.capacity() << endl;
    for(int i = 0;i < v3.size();i++)
    {
        cout << v3[i] << " ";
    }
    cout << endl;


    cout << v4.size() << endl;
    cout << v4.capacity() << endl;
    for(int i = 0;i < v4.size();i++)
    {
        cout << v4[i] << " ";
    }
    cout << endl;

    for(vector<int>::size_type i = 0;i != 24;i++)
    {
        v1.push_back(i);
    }
    cout << v1.size() << endl;
    cout << v1.capacity() << endl;
    v1.reserve(50);
    cout << v1.size() << endl;
    cout << v1.capacity() << endl;
    v1.push_back(56);
    cout << v1.size() << endl;
    cout << v1.capacity() << endl;
    v1.shrink_to_fit();
    cout << v1.size() << endl;
    cout << v1.capacity() << endl;

    for(auto it = v1.begin();it != v1.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    v1.erase(v1.begin());
    for(auto it = v1.begin();it != v1.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    v1.erase(v1.end()-5,v1.end());
    for(auto it = v1.begin();it != v1.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;

    for(auto it = v1.begin();it != v1.end();it++)
    {
        if((*it % 2) != 0)
        {
            v1.erase(it);
        }
        else
        {
            it++;
        }
    }

    for(auto it = v1.begin();it != v1.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;
    return 0;
}
3.5.5list

list的好处是每次插入或者删除一个元素,就置配或释放一段空间,因此,对于list空间的运用要绝对的精准,一点也不浪费,而且对于任何位置的插入和删除,list永远是常数时间

list采用的迭代器:双向迭代器(bidirectional iterator)

#include <iostream>
#include <list>
#include <string>
using namespace std;
template <typename T>
void func(list<T> &l)
{
    for(auto it = l.begin();it != l.end();it++)
    {
        cout << *it << " ";
    }
    cout << endl;
}
class Test
{
    public:
        int m_a;
        string m_name;
    public:
        Test()
        {
            cout << "Test" << endl;
        }
        Test(int a,string n):m_a(a),m_name(n)
        {
            cout << m_a << "Test's create with one num" << endl;
        }
        Test(const Test &obj)
        {
            cout << "Test's copy create" << endl;
            this->m_a = obj.m_a;
            this->m_name = obj.m_name;
        }
        ~Test()
        {
            cout << "~Test" << endl;
        }
        bool operator==(const Test &t)
        {
            return this->m_a == t.m_a && this->m_name == t.m_name;
        }
};
ostream& operator<<(ostream &out,Test &t)
{
    out << t.m_a << " " << t.m_name << endl;
    return out;
}
int main(int argc, const char *argv[])
{
    list<int> ll(100,1);
    cout << ll.size() << endl;
    func(ll);
    list<int> l2(ll.begin(),ll.end());
    list<int> l3(l2);
    Test t1(1,"aaa");
    Test t2(2,"bbb");
    Test t3(3,"ccc");
    Test t4(4,"ddd");
    Test t5(5,"eee");
    Test t6(6,"fff");
    list<Test> l;
    l.push_back(t1);
    l.push_back(t2);
    l.push_back(t3);
    l.push_back(t4);

    l.push_front(t5);
    l.push_front(t6);
    l.push_front(Test(7,"ggg"));

    l.emplace_front(8,"ppp");
    l.emplace_back(9,"www");
    l.emplace(l.begin(),10,"ooo");
    func(l);

    l.pop_back();
    l.pop_front();
    func(l);
    cout << l.front() << endl;
    cout << l.back() << endl;

    l.resize(15,t4);
    func(l);

    Test t[5] = {Test{1,"aa"},Test{2,"bb"},Test{3,"cc"},Test{4,"dd"},Test{5,"ee"}};
    l.insert(l.begin(),t[0]);
    l.insert(l.end(),t,t+5);
    func(l);

//    l.erase(++l.begin(),--l.end());
//    func(l);
//    l.erase(l.begin());
//    func(l);
    l.unique();
    func(l);
    l.sort();
    return 0;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值