c++ - c++11(1)

news2024/12/25 9:04:24

文章目录

  • 前言
    • 一、统一的列表初始化
      • 1、使用{ }初始化
      • 2、 std::initializer_list
    • 二、声明
      • 1、auto
      • 2、decltype
      • 3、nullptr
    • 三、范围for循环
    • 四、右值引用
      • 1、左值引用和右值引用
      • 2、左值引用和右值引用的比较
      • 3、左值引用的使用场景
      • 4、右值引用的使用场景
      • 5、完美转发


前言


一、统一的列表初始化

1、使用{ }初始化

(1)概念

C++11扩大了用大括号括起的列表(初始化列表)的使用范围,使其可用于所有的内置类型和用户自定义的类型,使用初始化列表时,可添加等号(=),也可不添加。

(2)演示:

//日期类
class Date
{
public:
	Date(int year = 1,int month = 1,int day = 1)
		:_year(year),
		_month(month),
		_day(day)
	{}
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};

//统一的列表初始化
void test01()
{
	//对一个数组
	int arr[] = { 1,2,3,4,5 };
	//也可以将等号舍去 int arr[]{ 1,2,3,4,5 };
	cout << "arr: ";
	for (auto& e : arr)
		cout << e << " ";
	cout << endl;

	//对一个对组
	pair<int, int> p = { 1,1 };
	//p{1,1}
	cout << "p: ";
	cout << p.first << " " << p.second << endl;

	//对一个变量
	int a = { 1 };
	//a{1}
	cout << "a: ";
	cout << a << endl;

	//自定义类型
	Date d = { 1,2,3 };
	//Date d{1,2,3}
	cout << "d: ";
	d.Print();
}

在这里插入图片描述

2、 std::initializer_list

(1)介绍
在这里插入图片描述

(1)此类型用于访问 C++ 初始化列表中的值,该列表是 const T 类型的元素列表。
(2)这种类型的对象是由编译器根据初始化列表声明自动构造的,该定义列表声明是用大括号括起来的逗号分隔的元素列表:auto il = { 10, 20, 30 }; //IL 的类型是initializer_list
(3)具体了解: std::initializer_list

(2)使用场景

std::initializer_list一般是作为构造函数的参数,C++11对STL中的不少容器就增加std::initializer_list作为参数的构造函数,这样初始化容器对象就更方便了。
在这里插入图片描述
也可以作为operator=的参数,这样就可以用大括号赋值。
在这里插入图片描述
(3)演示:

//std::initializer_list
void test02()
{
	//直接使用
	initializer_list<int> ls = { 1,2,3,4,5};
	cout << "ls: ";
	for (auto e : ls)
		cout << e << " ";
	cout << endl;

	//作为参数使用
	//隐式类型转化为initializer_list类型再使用构造函数构造
	vector<int> arr = { 1,2,3,4,5 };	
	cout << "arr: ";
	for (auto e : arr)
		cout << e << " ";
	cout << endl;
}

(4)注意
在这里插入图片描述

二、声明

1、auto

(1)介绍

在C++98中auto是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以auto就没什么价值了。C++11中废弃auto原来的用法,将 其用于实现自动类型腿断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初 始化值的类型。
注意:在C++中,auto 关键字不能直接用作函数参数的类型声明。auto 的设计初衷是用于自动类型推导,但仅限于在编译时能够根据初始化表达式确定类型的上下文中,如局部变量声明、for 循环的初始化表达式等。函数参数的类型必须在编译时就已经明确,因为函数声明和定义必须清晰地指明其接受哪些类型的参数,以便编译器进行类型检查和函数重载解析。

(2)演示:

//作为函数返回值
auto func()
{
	//推导为int
	return 1;
}

void test03()
{
	//自动推导内置类型
	auto a = 10;
	cout << "a:" << a << endl;

	//自动推导自定义类型
	auto b = Date(1, 1, 1);
	cout << "b:";
	b.Print();

	//推导复杂的类型
	vector<int> arr = {1,2,3};
	//vector<int>::iterator = arr.begin();
	auto c = arr.begin();
	cout << "c:" << *c << endl;

	//作为返回值
	auto d = func();
	cout << typeid(d).name() << endl;
}

2、decltype

(1)介绍

关键字decltype将变量的类型声明为表达式指定的类型。

(2)演示

//通过模板类型推导类型
template<class T1, class T2>
void func02(T1 t1, T2 t2)
{
	//通过t1*t2的结果类型来声明
	decltype(t1 * t2) p3;
	cout << "p3:" << typeid(p3).name() << endl;
}

void test04()
{
	//通过a*b的表达式的类型来声明ret的类型
	int a = 10;
	int b = 10;
	double c = 1.1;
	//通过a*b的结果类型来声明
	decltype(a * b) p1;
	//通过a*c的结果类型来声明
	decltype(a * c) p2;
	cout << "p1:" << typeid(p1).name() << endl;
	cout << "p2:" << typeid(p2).name() << endl;
	func02(1, 1);
}

3、nullptr

(1)介绍

由于C++中NULL被定义成字面量0,这样就可能回带来一些问题,因为0既能指针常量,又能表示
整形常量。所以出于清晰和安全的角度考虑,C++11中新增了nullptr,用于表示空指针。

(2)演示

//整形类型
void func03(int a)
{
	cout << "void func03(int a)" << endl;
}

//重载
//指针类型
void func03(void* a)
{
	cout << "void func03(void* a)" << endl;
}

void test05()
{
	func03(0);
	func03(NULL);
	func03(nullptr);
}

![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/48e3cbb09ddc44ec84b85101a432de80.png

上述出现了NULL也调用整形重载函数,出现了误用的情况,而使用nullptr就不会出现误用的情况,所以使用空指针时建议使用nullptr

三、范围for循环

1、介绍

C++11 引入了范围 for 循环(Range-based for loop),也被称为基于范围的 for 循环,它提供了一种更加简洁和直观的方式来遍历容器(如数组、向量 std::vector、列表 std::list、字符串等)中的元素。这种循环方式不仅减少了代码量,还提高了代码的可读性和可维护性。

2、语法

for (declaration : expression)  
    statement

declaration:定义了一个变量,用于在每次迭代中存储容器中的当前元素。这个变量的类型会自动根据容器的元素类型推导出来(需要C++11 的自动类型推导功能auto)。
expression:表示一个容器(如数组、向量、字符串等),或者是一个可以返回迭代器对的表达式(如begin() 和 end() 成员函数)。
statement:在每次迭代中执行的代码块。

3、演示

//范围for
void test06()
{
	//遍历数组
	int arr[] = { 1,2,3,4.5 };
	cout << "arr: ";
	for (auto e : arr)//auto &e 取引用
	{
		cout << e << " ";
	}
	cout << endl;

	//遍历vector容器
	vector<int> v = { 1,2,3,4,5 };
	cout << "v: ";
	for(auto &e:v)
	{
		cout << e << " ";
	}
	cout << endl;
}

在这里插入图片描述

四、右值引用

1、左值引用和右值引用

传统的C++语法中就有引用的语法,而C++11中新增了的右值引用语法特性,之前学习的引用就叫做左值引用。无论左值引用还是右值引用,都是给对象取别名。

(1)什么是左值、什么是左值引用

左值是一个表示数据的表达式(如变量名或解引用的指针),我们可以获取它的地址+可以对它赋值,左值可以出现赋值符号的左边,右值不能出现在赋值符号左边。定义时const修饰符后的左值,不能给他赋值,但是可以取它的地址。左值引就是给左值的引用,给左值取别名。

//左值
void test07()
{
	int a = 10;
	int* b = new int(10);
	const int c = 10;
	//以上abc都是左值

	//下面对左值取引用
	int& la = a;
	int*& lb = b;
	const int& lc = c;
}

(2)什么是右值、什么是右值引用

右值也是一个表示数据的表达式,如:字面常量、表达式返回值,函数返回值(这个不能是左值引用返回)等等,右值可以出现在赋值符号的右边,但是不能出现出现在赋值符号的左边,右值不能取地址。右值引用(&&)就是对右值的引用,给右值取别名。

//右值
int func04()
{
	return 1;
}

void test08()
{
	int x = 10, y = 10;

	//下面是右值
	1;
	x + y;
	func04();

	//对右值取引用
	int&& a = 10;
	int&& b = x + y;
	int&& c = func04();
}

2、左值引用和右值引用的比较

(1)左值引用不能引用右值,但是加const修饰的左值引用能引用右值。
(2)右值引用不能引用左值,但是通过move(将左值强制转化为右值)左值,就能被右值引用了。

void test09()
{	
	//err
	//int& a = 10;	左值引用不能引用右值

	const int& a = 10;	//加const修饰后就可引用右值了

	//err
	int b = 10;
	//int&& c = b;	//右值引用不能引用左值
	int&& c = move(b);//通过move后就可以引用左值了
}

3、左值引用的使用场景

一般作为参数和作为返回值,这样减少拷贝来提高效率。

//返回值:值返回
//参数:值传递
string func05(string s)
{
	return s;
}
//返回值:引用返回
//参数:引用传递
string& func06(string& s)
{
	return s;
}

void test10()
{
	string s = "abc";
	string s1 = func05(s);	//调用值传递版本
	string s2 = func06(s);	//调用引用传递版本
}

在这里插入图片描述

4、右值引用的使用场景

(1)右值引用的作用:

移动语义:允许对象以更高效的方式传递其资源(如动态分配的内存、文件句柄等),而不是复制它们。当一个对象通过右值引用传递给函数时,该函数可以“窃取”对象的资源,避免不必要的复制,然后将其状态设置为安全可析构的状态(如空指针、零大小等)。

(1)实现移动拷贝构造和移动赋值重载
对下面链表增加移动拷贝构造和移动赋值重载

list.h

namespace xu
{
    // List的结点类
    template<class T>
    struct ListNode
    {
        ListNode<T>* _pPre; //后继指针
        ListNode<T>* _pNext; //前驱指针
        T _val; //数据
        //构造结点
        ListNode(const T& val = T()) :_val(val), _pPre(nullptr), _pNext(nullptr)
        {}
    };


    //List的正向迭代器类
    //Ref为T& Ptr为T*
    template<class T, class Ref, class Ptr>
    class ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef ListIterator<T, Ref, Ptr> Self;
    public:
        //构造函数 ,获取一个结点指针
        ListIterator(const PNode & pNode = nullptr, const PNode& const P = nullptr) :_pNode(pNode),_P(P)
        {}
        Ref operator*()
        {
            assert(_P != _pNode);

            return _pNode->_val;
        }
        Ptr operator->()
        {
            return &(operator*());
        }
        Self& operator++()
        {
            _pNode = _pNode->_pNext;
            return *this;
        }
        Self operator++(int)
        {
            Self tmp(_pNode);
            _pNode = _pNode->_pNext;
            return tmp;
        }
        Self& operator--()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }
        Self& operator--(int)
        {
            Self tmp(_pNode);
            _pNode = _pNode->_pPre;
            return tmp;
        }
        bool operator!=(const Self& l)
        {
            return l._pNode != _pNode;
        }
        bool operator==(const Self& l)
        {
            return l._pNode == _pNode;
        }
        PNode get()
        {
            return _pNode;
        }
    private:
        PNode _pNode;
        PNode _P;
    };

    //List的反向迭代器类
    template<class T, class Ref, class Ptr>
    class Reverse_ListIterator
    {
        typedef ListNode<T>* PNode;
        typedef Reverse_ListIterator<T, Ref, Ptr> Self;
    public:
        Reverse_ListIterator(const PNode& pNode = nullptr, const PNode& const P = nullptr) :_pNode(pNode), _P(P)
        {}
        Ref operator*()
        {
            assert(_P != _pNode ->_pPre);
            return _pNode->_pPre->_val;
        }
        Ptr operator->()
        {
            return &(operator*());
        }
        Self& operator++()
        {
            _pNode = _pNode->_pPre;
            return *this;
        }
        Self operator++(int)
        {
            Self tmp(_pNode);
            _pNode = _pNode->_pPre;
            return tmp;
        }
        Self& operator--()
        {
            _pNode = _pNode->_pNext;
        }
        Self& operator--(int)
        {
            Self tmp(_pNode);
            _pNode = _pNode->_pNext;
            return tmp;
        }
        bool operator!=(const Self& l)
        {
            return l._pNode != _pNode;
        }
        bool operator==(const Self& l)
        {
            return l._pNode == _pNode;
        }
        PNode get()
        {
            return _pNode;
        }
    private:
        PNode _pNode;
        PNode _P;
    };


    //list类
    template<class T>
    class list
    {
        typedef ListNode<T> Node;
        typedef Node* PNode;
    public:
        typedef ListIterator<T, T&, T*> iterator;
        typedef ListIterator<T, const T&, const T*> const_iterator;
        typedef Reverse_ListIterator<T, T&, T*> reverse_iterator;
        typedef Reverse_ListIterator<T, const T&, const T*> reverse_const_iterator;
    public:
        //默认构造

        list() 
        {   //构造一个哨兵位结点
            CreateHead(); 
        }
        list(int n, const T& value = T())
        {
            //构造一个哨兵位结点
            CreateHead();

            //将元素尾插入
            while (n != 0)
            {
                push_back(value);
                --n;
            }
        }
        template <class Iterator>
        list(Iterator first, Iterator last)
        {
            //构造一个哨兵位结点
            CreateHead();
            //将元素尾插入
            while (first != last)
            {
                push_back(*first);
                ++first;
            }
        }

        //拷贝构造
        list(const list<T>& l)
        {
            //构造一个哨兵位结点
            CreateHead();

            //遍历+将元素尾插入
            PNode tmp = l._pHead->_pNext;
            while (tmp != l._pHead)
            {
                //尾插
                push_back(tmp->_val);
                tmp = tmp->_pNext;
            }

            cout << " list(const list<T>& l)" << endl;
        }
       
        list<T>& operator=(const list<T>& l)
        {
            //清空原链表
            clear();

            //遍历+将元素尾插入
            PNode tmp = l._pHead->_pNext;
            while (tmp != l._pHead)
            {
                push_back(tmp->_val);
                tmp = tmp->_pNext;
            }
            return *this;
        }

        ~list()
        {
            //清空链表
            clear();
            //删除哨兵位结点
            delete _pHead;
            _pHead = nullptr;
        }

        ///
        // List Iterator
        iterator begin()
        {
            return iterator(_pHead->_pNext, _pHead);
        }
        iterator end()
        {
            return iterator(_pHead, _pHead);
        }

        const_iterator begin() const
        {
            return const_iterator(_pHead->_pNext, _pHead);
        }
        const_iterator end()const
        {
            return const_iterator(_pHead, _pHead);
        }

        reverse_iterator rbegin()
        {
            return reverse_iterator(_pHead, _pHead);
        }
        reverse_iterator rend()
        {
            return reverse_iterator(_pHead ->_pNext, _pHead);
        }

        reverse_const_iterator rbegin() const
        {
            return reverse_const_iterator(_pHead, _pHead);
        }
        reverse_const_iterator rend()const
        {
            return reverse_const_iterator(_pHead->_pNext, _pHead);
        }


           
             size_t size()const
            {
                PNode tmp = _pHead->_pNext;

                size_t count = 0;
                while (tmp != _pHead)
                {
                    tmp = tmp->_pNext;
                    ++count;
                }
                return count;
            }
            bool empty()const
            {
                return _pHead == _pHead->_pNext;
            }


            
            // List Access
            T& front()
            {
                assert(!empty());
                return _pHead->_pNext->_val;
            }
            const T& front()const
            {
                assert(!empty());
                return _pHead->_pNext->_val;
            }
            T& back()
            {
                assert(!empty());
                return _pHead->_pPre->_val;
            }
            const T& back()const
            {
                assert(!empty());
                return _pHead->_pPre->_val;
            }


            
            // List Modify
            void push_back(const T & val) { insert(end(), val); }
            void pop_back() { erase(--end()); }
            void push_front(const T & val) { insert(begin(), val); }
            void pop_front() { erase(begin()); }

            // 在pos位置前插入值为val的节点
            iterator insert(iterator pos, const T & val)
            {
                //创造一个结点
                PNode tmp = new Node(val);

                //获取迭代器中的指针
                PNode _pos = pos.get();

                //进行插入
                PNode prv = _pos->_pPre;
                prv->_pNext = tmp;
                tmp->_pPre = prv;
                tmp->_pNext = _pos;
                _pos->_pPre = tmp;

                //返回新迭代器
                return iterator(tmp);
            }
            // 删除pos位置的节点,返回该节点的下一个位置
            iterator erase(iterator pos)
            {
                //判断是否为哨兵位结点
                iterator it = end();
                assert(pos != it);

                //获取迭代器结点指针
                PNode tmp = pos.get();

                //进行删除
                PNode next = tmp->_pNext;
                PNode prv = tmp->_pPre;
                prv->_pNext = next;
                next->_pPre = prv;
                delete tmp;
                tmp = nullptr;

                //返回被删除结点的下一个位置的结点迭代器
                return iterator(next);
            }
          
            void clear()
            {
                //保存有效结点位置
                PNode tmp = _pHead->_pNext;

                //遍历删除
                while (tmp != _pHead)
                {
                    PNode p = tmp->_pNext;
                    delete tmp;
                    tmp = p;
                }
                //重新指向
                _pHead->_pNext = _pHead;
                _pHead->_pPre = _pHead;
            }

            void swap(list<T>& l)
            {
                std::swap(_pHead, l._pHead);
            }

        private:
            //让哨兵位结点指向自己
            void CreateHead()
            {
                _pHead = new  Node;
                _pHead->_pNext = _pHead;
                _pHead->_pPre = _pHead;
            }
            PNode _pHead;   //哨兵位结点
        };
    };

实现移动拷贝构造

//移动拷贝
list(list<T>&& l):_pHead(nullptr)
{
    //构造一个哨兵位结点
    CreateHead();
    //交换链表头节点
    std::swap(_pHead, l._pHead);
    cout << " list(list<T>&& l):_pHead(nullptr)" << endl;
}

移动拷贝构造和普通拷贝构造比较
在传右值时是调用移动拷贝构造,在传左值时是调用普通拷贝构造。
场景1:
用右值传参时,分别普通拷贝构造和移动拷贝构造的效率比较。
在这里插入图片描述
场景2:
用左值传参,分别调用移动拷贝构造(通过move来转化)、普通拷贝构造。
在这里插入图片描述

实现移动赋值重载

list<T>& operator=(list<T>&& l)
{
    //清空原链表
    clear();

    std::swap(_pHead, l._pHead);
    return *this;
}

移动赋值重载构造和赋值重载比较:与移动拷贝构造和普通拷贝构造类似。

(2)当需要返回局部变量引用时,通过左值引用返回的话,可能会造成访问已经销毁的空间。此时只能使用传值返回了,传值返回的临时变量是右值,如果存在移动拷贝构造,则会调用移动拷贝构造,这样就会提高效率。

//返回左值引用可能造成访问冲突
//err
string & func07()
{
	string ret = "abc";
	return ret;
}
//传值返回
string  func07()
{
	string ret = "abc";
	return ret;
}
//
void   func08()
{
	string ret = func07();
}

在这里插入图片描述

5、完美转发

(1)万能引用

(1)、在模板中&& 不是作为右值引用,而是作为万能引用,即可以引用右值也能够引用左值。
(2)、模板的万能引用只是提供了能够接收同时接收左值引用和右值引用的能力,但是引用类型的唯一作用就是限制了接收的类型,后续使用中都退化成了左值,我们希望能够在传递过程中保持它的左值或者右值的属性, 就需要用我们下面学习的完美转发

template<typename T>
void func08(T && t)	//万能引用
{
}

(2)完美转化
std::forward 完美转发在传参的过程中保留对象原生类型属性。

//左值引用
void func09(const int &a)
{
	cout << "void func09(const int &a)" << endl;
}

//右值引用
void func09(int &&a)
{
	cout << " void func10(int &&a)" << endl;
}


template<typename T>
void func08(T && t)
{
	func09(std::forward<T>(t));
}

void test12()
{
	int a = 10;
	//左值
	func08(a);

	//右值
	func08(10);
}

在这里插入图片描述
(3)运用完美转发实现链表尾插右值引用版本

void push_back(T&& val)
{ 
    insert(end(), std::forward<T>(val));
}

// 在pos位置前插入值为val的节点
iterator insert(iterator pos, T&& val)
{
    //创造一个结点
    PNode tmp = new Node(val);

    //获取迭代器中的指针
    PNode _pos = pos.get();

    //进行插入
    PNode prv = _pos->_pPre;
    prv->_pNext = tmp;
    tmp->_pPre = prv;
    tmp->_pNext = _pos;
    _pos->_pPre = tmp;

    //返回新迭代器
    return iterator(tmp);
}

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

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

相关文章

在百度飞浆中搭建pytorch环境

文章目录 1 先检查创建的环境2 创建虚拟环境3 最终结果 1 先检查创建的环境 选择GPU版本 检查python版本 2 创建虚拟环境 虚拟环境的创建 python3 -m venv env_name # (python3 -m 路径 环境名)激活虚拟环境 source env_name/bin/activate这里注意&#xff0c;同名文件…

MySQL的InnoDB的页里面存了些什么

文章目录 创建新表页的信息新增一条数据根据页号找数据信息脚本代码py_innodb_page_info根据地址计算页号根据页号计算起始地址 主要介绍数据页里面有哪些内容&#xff0c;一行数据在文件里面是怎么组织的 创建新表页的信息 CREATE TABLE test8 (id bigint(20) NOT NULL AUTO…

Android开发-使用FFmpeg-Android进行音视频处理

使用 FFmpeg-Android 进行音视频处理 1. 前言2. FFmpeg-Android 简介3. 功能介绍及实现3.1. 视频字幕添加Kotlin 代码示例&#xff1a;3.2. 尺寸剪切Kotlin 代码示例&#xff1a;3.3. 添加或去除水印Kotlin 代码示例&#xff1a;3.4. 时长截取Kotlin 代码示例&#xff1a;3.5. …

【十万个为什么】强磁场环境用什么编码器好?磁编为什么不怕强磁场?磁编与光编哪一个抗干扰强?

系列文章目录 1.元件基础 2.电路设计 3.PCB设计 4.元件焊接 5.板子调试 6.程序设计 7.算法学习 8.编写exe 9.检测标准 10.项目举例 11.职业规划 文章目录 前言一、案例场景1&#xff1a;场景2&#xff1a; 二、为什么磁编可以在磁场中工作三、磁编为什么不怕强磁场&#xf…

LVS实战项目

LVS简介 LVS:Linux Virtual Server&#xff0c;负载调度器&#xff0c;内核集成&#xff0c;章文嵩&#xff0c;阿里的四层SLB(Server LoadBalance)是基于LVSkeepalived实现。 LVS集群的类型 lvs-nat &#xff1a; 修改请求报文的目标IP, 多目标 IP 的 DNAT lvs-dr &#xff…

vpp编译安装(Ubuntu 16.04)

1、编译 git clone -b stable/1801 https://github.com/FDio/vpp.git cd vpp ./extras/vagrant/build.sh && make 报错 解决&#xff1a; 操作系统是Ubuntu 18.04.5 换成ubuntu 16即可

step11:打包qml程序

文章目录 0.文章介绍1.增加环境变量2.复制RDU.exe3.找到Qt安装路径4.操作qt 6.4.3&#xff08;minGW&#xff09;命令框 0.文章介绍 1.增加环境变量 电脑里安装了两个版本的QT&#xff0c;最好把现在打包的QT版本环境变量移到最前面 添加完成环境变量之后&#xff0c;再在wi…

力扣高频SQL 50题(基础版)第四十一题之1517.查找拥有有效邮箱的用户

文章目录 力扣高频SQL 50题&#xff08;基础版&#xff09;第四十一题1517.查找拥有有效邮箱的用户题目说明实现过程准备数据实现方式结果截图总结 力扣高频SQL 50题&#xff08;基础版&#xff09;第四十一题 1517.查找拥有有效邮箱的用户 题目说明 表: Users -----------…

c++语言学习,isalnum()函数分析

1&#xff1a;isalnum() 函数说明&#xff1a; 检查参数c,是否为英文字母或阿拉伯数字 2&#xff1a;函数原型&#xff1a; int isalnum(int c) 3&#xff1a;函数参数&#xff1a; 参数c&#xff0c;为检测字符 4&#xff1a;返回值&#xff1a; 若参数c为字母或数字&#…

全网最详细教你学习LVS(Linux virual server)

LVS 官网 : http://www.linuxvirtualserver.org/ //&#xff08;可参考&#xff09; 一、LVS定义&#xff1a; 是一个基于 Linux 操作系统的开源软件负载均衡项目。 LVS 主要用于实现服务器的负载均衡和高可用性。它工作在网络的第四层&#xff0c;可以对…

ERP帮助中心的卓越实践:以用友ERP为例的成功之路

引言 在数字化转型的浪潮中&#xff0c;企业资源规划&#xff08;ERP&#xff09;系统作为企业管理的核心工具&#xff0c;其有效应用直接关系到企业的运营效率与竞争力。然而&#xff0c;ERP系统的复杂性和多功能性往往让用户在初识阶段感到困惑。因此&#xff0c;构建一个高…

Boost搜索引擎:网络模块的构建

网页展示界面 每个网页界面都有他相应的代码构成 按F12键 就会出现.html文件代码 上图是csdn当前网页文件代码&#xff0c;所以说要想&#xff0c;设计好看的网页文件需要去学对应的只是&#xff0c;我没有怎么接触过&#xff0c;所以网页代码就不能为大家讲解了。 网页展示的…

软件设计之JavaScript(2)

软件设计之JavaScript(2) 【狂神说Java】JavaScript最新教程通俗易懂 学习内容&#xff1a; 软件开发技能点参照&#xff1a;软件开发&#xff0c;小白变大佬&#xff0c;这套学习路线让你少走弯路是认真的&#xff0c;欢迎讨论 软件开发技能点顺序参照&#xff1a;Java学习…

【鸿蒙开发基础学习】组件导航 (Navigation)

组件导航 (Navigation) Navigation 是路由容器组件&#xff0c;一般作为首页的根容器&#xff0c;包括单栏(Stack)、分栏(Split)和自适应(Auto)三种显示模式。Navigation 组件适用于模块内和跨模块的路由切换&#xff0c;一次开发&#xff0c;多端部署场景。通过组件级路由能力…

视频剪辑SDK,人脸美化与滤镜特效,焕发直播新活力

在数字化浪潮席卷全球的今天&#xff0c;直播已成为连接品牌与消费者、创作者与观众的重要桥梁。为了在激烈的直播竞争中脱颖而出&#xff0c;提供高质量、富有创意的直播内容成为关键。美摄科技&#xff0c;作为视频处理技术的先行者&#xff0c;携手其强大的视频剪辑SDK解决方…

Python:构建一个算法预测类型

准确工作&#xff1a;需要下载music.csv 已上传 构建模型内容&#xff1a; import pandas as pd music_data pd.read_csv(music.csv) # music_data Xmusic_data.drop(columns[genre]) # 删除的那一列的名字为genre Ymusic_data[genre] # 访问指定的列 Y 预测用的是决策树&…

leetcode日记(65)组合

一眼递归&#xff0c;第一版写出的代码写成了排列组合&#xff0c;然后修改后&#xff1a; class Solution { public:vector<vector<int>> combine(int n, int k) {vector<int> vec;vector<vector<int>> result;for(int i1;i<n;i){vec.push_…

[MAE] Masked Autoencoders Are Scalable Vision Learners

1、目的 NLP领域的自监督预训练非常成功&#xff0c;CV领域可以参考其masked autoencoding方法。主要挑战有&#xff1a; 1&#xff09;CNN不会直接用mask tokens或者positional embeddings&#xff0c;而是在规则网格上运算 -> Vision Transformers (ViT) 2&#xff09;Lan…

SQL注入sqli-labs-master关卡四

第四关如下&#xff1a; 查看其php代码&#xff1a;发现其与前三关的区别就在于id这里。即使用")进行逃离。 则步骤与前三关一致&#xff0c;细节上改变即可。 输入?id1判断是字符型还是数字型注入 输入?id-1") union select 1,2,3--只显示2&#xff0c;3列。 输入…

C++从入门到起飞之——深浅拷贝string类补充 全方位剖析!

​ &#x1f308;个人主页&#xff1a;秋风起&#xff0c;再归来~&#x1f525;系列专栏&#xff1a;C从入门到起飞 &#x1f516;克心守己&#xff0c;律己则安 目录 1、浅拷贝 2、深拷贝 3、现代版写法的拷贝构造和赋值重载 4、再探swap! 5、写实拷贝&#xff…