【C++】C++11的新特性(上)

引入 

   C++11作为C++标准的一个重要版本,引入了许多令人振奋的新特性,极大地丰富了这门编程语言的功能和表达能力。本章将为您介绍C++11的一些主要变化和改进,为接下来的章节铺垫。

  

文章目录

引入

一、列表初始化

1、1 {} 初始化

1、2 std::initializer_list的介绍

二、声明

2、1 auto关键字的引入

2、2 decltype关键字

2、3 nullptr

三、智能指针

四、范围for

五、STL中一些变化

5、1 新容器

5、2 新接口

六、右值引用和移动语义

6、1 左值引用和右值引用

6、1、1 左值与左值引用 

6、1、2 右值与右值引用

6、2 左值引用与右值引用比较

6、3 右值引用的使用场景与意义

6、3、1 移动构造

6、3、2 移动赋值

七、总结


🙋‍♂️ 作者:@Ggggggtm 🙋‍♂️

👀 专栏:C++ 👀

💥 标题:C++11 💥

❣️ 寄语:与其忙着诉苦,不如低头赶路,奋路前行,终将遇到一番好风景 ❣️ 

一、列表初始化

1、1 {} 初始化

  在C++98中,标准允许使用花括号{}对数组或者结构体元素进行统一的列表初始值设定。比如:

struct Point
{int _x;int _y;
};
int main()
{int array1[] = { 1, 2, 3, 4, 5 };int array2[5] = { 0 };Point p = { 1, 2 };return 0;
}

  在C++11中,引入了列表初始化的概念,允许我们使用花括号来初始化各种类型的对象,使其可用于所有的内置类型和用户自定义的类型,都可以使用统一的初始化语法,从而减少了初始化的歧义性和错误。 使用初始化列表时,可添加等号(=),也可不添加。具体如下:

class Date
{
public:Date(int year, int month, int day):_year(year), _month(month), _day(day){cout << "Date(int year, int month, int day)" << endl;}private:int _year;int _month;int _day;
};int main()
{int x1 = 1;int x2 = { 2 };int x3 { 2 };// 都是在调用构造函数Date d1(2022, 11, 22);Date d2 = {2022, 11, 11}; Date d3{ 2022, 11, 11 };return 0;
}

  我们发现,C++11列表初始化允许我们使用花括号来初始化各种类型的对象后,可能会在某些情况下带来一些方便,但实际上看起来还是有一点不适应的。

1、2 std::initializer_list的介绍

 std::initializer_list 是 C++11 标准库中引入的一个特殊容器,它用于方便地初始化数据。它允许我们在列表初始化(也称为花括号初始化)的情况下,以逗号分隔的值列表的形式传递一组元素。

  使用 std::initializer_list 可以将一组值作为参数传递给函数或构造函数,从而简化代码的编写,并提高可读性。它的主要作用是用于表示一个不可修改的序列,类似于数组或容器,但没有提供像容器操作那样丰富的接口。

下面是 sstd::initializer_list 的主要特点和用法:

  1. 定义和声明:std::initializer_list 是一个模板类,位于 <initializer_list> 头文件中。可以通过以下语法来声明并初始化一个 std::initializer_list 对象:

    std::initializer_list<T> list = {value1, value2, ...};
  2. 使用范围:std::initializer_list 可以用于任何需要一组值作为参数的上下文中,例如函数参数、构造函数参数等。

  3. 迭代器和大小:std::initializer_list 提供了类似容器的迭代器和大小函数,可以使用 begin()end() 来获取迭代器,size() 来获取序列的大小。

  4. 元素访问:std::initializer_list 并不提供随机访问元素的功能,只能顺序遍历元素。可以使用 std::initializer_list 的迭代器或范围-based for 循环来访问元素。

  具体我们可结合如下实例理解:

int main()
{// 调用支持list (initializer_list<value_type> il)类似这样的构造函数vector<int> v1 = { 1, 2, 3, 4, 5, 6 };vector<int> v2{ 1, 2, 3, 4, 5, 6 };list<int> lt1 = { 1, 2, 3, 4, 5, 6 };list<int> lt2{ 1, 2, 3, 4, 5, 6 };auto x = { 1, 2, 3, 4, 5, 6 };cout << typeid(x).name() << endl;vector<Date> v4 = { { 2022, 1, 1 }, {2022, 11, 11} };string s1 = "11111";// 构造map<string, string> dict = { { "sort", "排序" }, { "insert", "插入" } };// 赋值重载initializer_list<pair<const string, string>> kvil = { { "left", "左边" }, { "left", "左边" } };dict = kvil;return 0;
}

  我们先看一下运行结果:

  同时我们再看一下C++的标准库的介绍文档:

二、声明

2、1 auto关键字的引入

  C++11引入了 auto 关键字,允许变量的类型根据初始化表达式进行自动推导。这种类型推导机制不仅简化了代码书写,还减少了代码中的重复信息,提高了代码的可读性和维护性。

  在C++98中 auto 是一个存储类型的说明符,表明变量是局部自动存储类型,但是局部域中定义局部的变量默认就是自动存储类型,所以 auto 就没什么价值了。C++11中废弃 auto 原来的用法,将其用于实现自动类型推断。这样要求必须进行显示初始化,让编译器将定义对象的类型设置为初始化值的类型。具体我们看如下代码:

int main()
{int i = 10;auto p = &i;auto pf = strcpy;cout << typeid(p).name() << endl;  // int *cout << typeid(pf).name() << endl; // char * (__cdecl*)(char *,char const *) 函数指针map<string, string> dict = { {"sort", "排序"}, {"insert", "插入"} };//如下auto的作用体现//map<string, string>::iterator it = dict.begin();auto it = dict.begin();return 0;
}

 auto关键字可以方便地简化代码,尤其是当变量类型较为复杂或使用模板时。它可以更灵活地适应不同的场景,并且减少了编写冗长类型名称的工作。

2、2 decltype关键字

  除了 auto 关键字外,C++11还引入了 decltype 关键字。decltype关键字则用于获取表达式的类型,而不是进行类型推导。它主要用于在编译时获取表达式的静态类型信息,并且保留了const、引用修饰符等特性。

  有些同学可能会感觉 auto 和 decltype 非常的相似。其实他们是有所区别的,具体看如下代码:

int main()
{int x = 10;// typeid拿到只是类型的字符串,不能用这个再去定义对象什么的//typeid(x).name() y = 20;  错误// decltype(x) intdecltype(x) y1 = 20.22;auto y2 = 20.22;cout << y1 << endl;cout << y2 << endl;return 0;
}

  运行结果如下图:

2、3 nullptr

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

#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

三、智能指针

  后面会专门对智能指针进行详细解释,此处就不再过多解释。

四、范围for

  C++11引入了范围for循环(Range-based for loop),可以更简洁地遍历容器或者其它可迭代对象的元素。具体使用方式是:“for (type variable : range)”。

  范围for循环的底层原理是通过迭代器(iterator)实现的。迭代器是访问容器内元素的一种方式,通过指向容器中的特定位置来遍历元素。范围for循环会自动遍历整个容器中的元素,并使用迭代器实现循环。

下面是范围for循环使用与底层原理的详解:

  1. 使用方式:
    • 针对容器:对于容器类型(比如vector、list等),范围for循环按顺序遍历容器中的每个元素,将每个元素赋值给变量,直到遍历完所有元素。
    • 针对数组:对于数组类型,范围for循环也能正常工作,类似于按顺序访问数组中的每个元素。
    • 自定义类型:如果要对自定义类型使用范围for循环,需要定义相应的迭代器接口或者提供begin()和end()成员函数,以便定义迭代的开始和结束位置。

示例代码如下:

std::vector<int> vec = {1, 2, 3, 4, 5};
for (int num : vec) {std::cout << num << " ";
}
// 输出:1 2 3 4 5int arr[] = {6, 7, 8, 9, 10};
for (int num : arr) {std::cout << num << " ";
}
// 输出:6 7 8 9 10
  1. 底层原理: 范围for循环的底层原理是通过使用迭代器实现的。迭代器是遍历容器或者其它可迭代对象的一种通用方式,提供了对元素的访问和操作。

    范围for循环的执行过程如下:

    • 对于容器类型,编译器会自动调用容器的begin()和end()成员函数获取容器的起始位置和结束位置的迭代器。
    • 对于数组类型,编译器将数组名转换为指向数组首元素的指针作为起始位置,以及指向数组最后一个元素的下一个位置的指针作为结束位置的迭代器。
    • 循环开始时,将起始位置的迭代器赋值给临时变量,然后判断迭代器是否达到结束位置,如果未达到,则执行循环体内的代码。
    • 每次循环迭代时,将迭代器指向的元素赋给循环变量,并使迭代器前进到下一个位置。
    • 直到迭代器达到结束位置,循环停止。

  范围for循环的引入简化了代码编写,使得遍历容器等可迭代对象更加方便和易读。

五、STL中一些变化

5、1 新容器

  C++11STL中引入了一些新的容器,如下图:

  C语言中的数组和C++11中的array是两种不同的数据类型,它们在以下几个方面存在一些对比和区别:

  1. 类型安全性:

    • C语言中的数组没有类型安全性检查,可以存储任意类型的数据。这就意味着您可以将一个元素类型不匹配的值赋给数组,这可能导致不可预测的结果或者错误。
    • C++11中的array是一个模板类,它对数组的类型进行了严格控制。只能存储指定类型的元素,当我们尝试存储不匹配的类型时,会在编译过程中产生错误,提供了更好的类型安全性。
  2. 大小确定性:

    • C语言中的数组在创建时需要显式指定大小,并且在使用时无法动态改变大小。这意味着数组长度是固定的,不能根据需求进行扩展或收缩。
    • C++11中的array也需要在创建时指定大小,但它提供了size()和max_size()等成员函数来获取数组的大小信息。同时,由于C++的特性,您可以使用动态数组(如vector)来代替array,动态数组具备灵活调整大小的能力。
  3. 内存管理:

    • C语言中的数组通过指针实现,其内存管理需要手动进行。数组的声明不会自动分配内存空间,需要使用malloc()或者calloc()等函数进行显式的内存分配和释放操作。
    • C++11中的array作为一个容器类,它在栈上分配内存,并在其作用域结束时自动释放。无需显式调用释放内存函数,这样更方便地管理和避免内存泄漏。
  4. 拷贝行为:

    • C语言中的数组不能直接进行拷贝,只能通过遍历数组元素进行手动赋值或者使用memcpy()函数来实现数组拷贝。
    • C++11中的array可以进行拷贝和移动操作,支持复制构造函数和赋值操作符的使用。

  forward_list 底层就是单链表。重点是unordered_map和unordered_set,其他的大家了解一下即可。

5、2 新接口

  如果我们再细细去看会发现基本每个容器中都增加了一些C++11的方法,但是其实很多都是用得比较少的。比如提供了cbegin和cend方法返回const迭代器等等,但是实际意义不大,因为begin和end也是可以返回const迭代器的,这些都是属于锦上添花的操作。
  实际上C++11更新后,容器中增加的新方法最后用的插入接口函数的右值引用版本:rempalce_back/emplace。下面我们会详细解释这些接口。

六、右值引用和移动语义

6、1 左值引用和右值引用

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

6、1、1 左值与左值引用 

  什么是左值?什么是左值引用?

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

  下面详细解释左值和左值引用:

  1. 左值:

    • 左值可以表示具有名称的变量、对象或数据成员,例如:int a = 10;、int array[10];、std::string str = "Hello";
    • 左值可以出现在赋值语句的左边或右边,例如:a = 20;、int b = a;;
    • 对一个左值进行取地址操作(&)时,可以获取其在内存中的位置;
    • 左值有持久性,意味着它们在表达式执行完后仍然存在。
  2. 左值引用:

    • 左值引用是使用符号“&”声明的引用类型,例如:int& ref = a;;
    • 左值引用可以将一个左值绑定到引用变量上,并通过引用直接访问绑定的左值;
    • 通过修改引用变量的值,也会影响所绑定的左值;
    • 左值引用可以作为函数的参数,使函数能够修改传递给它的变量的值;
    • 引用本身并不占用内存,它只是对绑定的左值进行别名。
int main()
{// 以下的p、b、c、*p都是左值int* p = new int(0);int b = 1;const int c = 2;// 以下几个是对上面左值的左值引用int*& rp = p;int& rb = b;const int& rc = c;int& pvalue = *p;return 0;
}

6、1、2 右值与右值引用

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

  右值引用(Rvalue Reference)是一种新的引用类型,用于绑定到右值上。它的语法是在类型前面添加两个连续的“&”符号,例如int&&。右值引用可以延长右值的生命周期,也可以让我们知道一个表达式是右值。

int main()
{double x = 1.1, y = 2.2;// 以下几个都是常见的右值10;x + y;fmin(x, y);// 以下几个都是对右值的右值引用int&& rr1 = 10;double&& rr2 = x + y;double&& rr3 = fmin(x, y);// 这里编译会报错:error C2106: “=”: 左操作数必须为左值// 10 = 1;// x + y = 1;// fmin(x, y) = 1;return 0;
}

   需要注意的是右值是不能取地址的,但是给右值取别名后,会导致右值被存储到特定位置,且可以取到该位置的地址,也就是说例如:不能取字面量10的地址,但是rr1引用后,可以对rr1取地址,也可以修改rr1。如果不想rr1被修改,可以用const int&& rr1 去引用,是不是感觉很神奇,这个了解一下实际中右值引用的使用场景并不在于此,这个特性也不重要。

int main()
{double x = 1.1, y = 2.2;int&& rr1 = 10;const double&& rr2 = x + y;rr1 = 20;rr2 = 5.5; // 报错return 0;
}

6、2 左值引用与右值引用比较

  左值引用总结:

  • 左值引用只能引用左值,不能引用右值。
  • 但是const左值引用既可引用左值,也可引用右值。

  右值引用总结:

  • 右值引用只能右值,不能引用左值。
  • 但是右值引用可以move以后的左值。

  具体我们可结合如下代码对左值引用和右值引用进行对比理解:

int main()
{// 左值引用只能引用左值,不能引用右值。int a = 10;int& ra1 = a; // ra为a的别名//int& ra2 = 10; // 编译失败,因为10是右值// const左值引用既可引用左值,也可引用右值。const int& ra3 = 10;const int& ra4 = a;// 右值引用只能右值,不能引用左值。int&& r1 = 10;// error C2440: “初始化”: 无法从“int”转换为“int &&”// message : 无法将左值绑定到右值引用int a = 10;int&& r2 = a;  // 错误// 右值引用可以引用move以后的左值int&& r3 = std::move(a);return 0;
}

  std::move是一个函数模板,定义在<utility>头文件中。它接受一个对象作为参数,并将其转换为右值引用。调用std::move后,原始对象的值仍然有效,但不能再保证其状态的有效性。std::move用于标记一个对象为可移动的,并将其传递给需要右值引用参数的函数,以实现资源的移动而不是复制。 

6、3 右值引用的使用场景与意义

6、3、1 移动构造

  我们知道,引用就是别名,其价值是为了减少拷贝。但是左值引用可以解决一些问题,同时也会遇到一些特殊情况解决不了拷贝的问题,具体如下:

  1. 做参数:a、减少拷贝,提高效率。b、做输出型参数,减少拷贝。
  2. 做返回值:a、引用返回可减少拷贝,提高效率。b、引用返回,可对返回值进行修改。

  但是并不是任何情况下返回值都可以是引用返回的。当返回值是临时变量(出了函数的作用域就销毁),就不可以作为引用返回。此时拷贝就是必不可少的。如下场景:

  这种情况就是避免不了需要进行拷贝,如下图:

  大部分编译器会对上述情况进行优化,不会产生中间的临时变量。直接使用str拷贝构造ret。那有没有很好的办法解决拷贝这种情况呢? 

  当然,我们也可以选择使用输出型参数,但是并不符合我们的使用习惯。具体如下:

   在C++11中,引入了移动构造。对比拷贝构造具体代码如下:

		// 移动构造string(string&& s):_str(nullptr), _size(0), _capacity(0){cout << "string(string&& s) -- 资源转移" << endl;swap(s);  // 资源转移}// 拷贝构造string(const string& s):_str(nullptr){cout << "string(const string& s) -- 拷贝构造(深拷贝)" << endl;//string tmp(s._str);//swap(s);_str = new char[s._capacity+1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}

  因为上述的 str 出了作用域就会销毁,我们将它视为将亡值,也就是右值。在既有拷贝构造和移动构造的情况下,编译器会匹配最移动构造。因为编译器会匹配最适合的参数。那么这里就不会采用拷贝构造了,而是选择移动构造。

  大部分编译器也会对上述进行优化。直接将 str 的资源转移到 ret 中。对比拷贝构造,我们能够明显的感觉出来,移动构造并没有进行申请资源,而是直接将将亡值的资源进行转移。移动构造减少了资源的申请和拷贝,提高了效率

6、3、2 移动赋值

  移动赋值与移动构造的原理大同小异。具体情况如下:

  上图的情况必须要进行拷贝构造和拷贝赋值。在C++11中引入移动构造后,同时也引入的移动赋值,对比移动复制和拷贝赋值具体代码如下:

        // 拷贝赋值string& operator=(const string& s){cout << "string& operator=(string s) -- 拷贝赋值(深拷贝)" << endl;string tmp(s);swap(tmp);return *this;}// 移动赋值string& operator=(string&& s){cout << "string& operator=(string s) -- 移动赋值(资源移动)" << endl;swap(s);return *this;}

  同样,这里的 str 会被识别成将亡值(右值),不会再调用拷贝构造和拷贝赋值。会调用移动构造和移动复制。移动构造和移动复制都是对右值的资源进行移动转移,减少了资源的申请和拷贝,从而提高效率。

  移动构造和移动赋值操作相对于拷贝构造和拷贝赋值操作的优点有以下几个方面:

  1. 性能更高:移动操作能够直接将资源(比如堆上的内存)从一个对象转移到另一个对象,而无需进行复制和销毁。这样可以消除额外的内存分配和释放开销,提高程序的性能。

  2. 减少内存拷贝:移动操作通过转移资源的所有权,避免了不必要的内存拷贝过程。对于大型对象或频繁进行内存操作的情况下,移动操作可以显著减少内存拷贝的次数,提高程序的效率。

  3. 资源管理效率:移动操作使得资源管理更加高效。在移动语义中,资源的所有权转移给了目标对象,源对象则不再拥有该资源。这意味着在移动后,源对象不再需要释放或删除资源。这样一来,在一些场景下可以避免重复释放资源或导致资源泄漏的问题。

  4. 容器的性能提升:使用移动构造和移动赋值可以有效提高容器操作(比如动态数组、动态字符串等)的性能。很多标准库容器都提供了移动语义的支持,通过移动操作,可以快速将对象移入或移出容器,而不会进行额外的拷贝操作。

  需要注意的是,移动操作通常适用于临时对象、将要被销毁的对象以及右值引用的情况下,而拷贝操作适用于需要保留原始对象的情况。对于用户自定义的类,为了充分利用移动操作,通常需要显式实现移动构造函数和移动赋值运算符,并确保正确处理资源的转移和释放。

七、总结

  由于C++11更新的重要内且常用容较多,就分为两篇内容进行详解。本篇内容的细节较多,重点在于右值引用和移动语义。下篇文章内容依然较多且为重要。本篇文章的讲解就到这里,感谢阅读ovo~

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

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

相关文章

java 桥接模式

桥接模式 桥接模式简介桥接模式的实现总结 桥接模式简介 桥接模式&#xff08;Bridge&#xff09;是将抽象部分与它的实现部分分离&#xff0c;使它们都可以独立地变化。它是一种对象结构型模式&#xff0c;又称为柄体(Handle and Body)模式或接口(Interfce)模式。 桥接模式基于…

正则表达式 之 断言详解

正则表达式的先行断言和后行断言一共有 4 种形式&#xff1a; (?pattern) 零宽正向先行断言(zero-width positive lookahead assertion)(?!pattern) 零宽负向先行断言(zero-width negative lookahead assertion)(?<pattern) 零宽正向后行断言(zero-width positive lookb…

NEOVIM学习笔记

GitHub - blogercn/nvim-config: A pretty epic NeoVim setup 一直使用vim&#xff0c;每次到了新公司都要配置半天&#xff0c;而且常常配置失败&#xff0c;很多插件过期不好用。偶然看到别人的NEO VIM&#xff0c;就试着用了一下&#xff0c;感觉还不错。 用来开发和阅读C代…

Kubernetes(K8s)基本环境部署

此处只做学习使用&#xff0c;配置单master环境。 一、环境准备 1、ip主机规划&#xff08;准备五台新机&#xff09;>修改各个节点的主机名 注意&#xff1a;关闭防火墙与selinux 节点主机名ip身份joshua1 kubernetes-master.openlab.cn 192.168.134.151masterjoshua2k…

Python爬虫实战案例——第三例

文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff01;严禁将文中内容用于任何商业与非法用途&#xff0c;由此产生的一切后果与作者无关。若有侵权&#xff0c;请联系删除。 起点中文网月票榜加密字体处理 字体加密的原理&#xff1a;就是将一种特定的…

11.Oracle中rollup函数详解

【基本介绍】 【格式】&#xff1a;group by rollup(字段1,字段2,字段3,...,字段n) 【说明】&#xff1a;rollup主要用于分组汇总&#xff0c;如果rollup中有n个字段&#xff0c;则会分别按【字段1】、【字段1,字段2】&#xff0c;【字段1,字段2,字段3】&#xff0c;...&#…

C++编辑修改PDF

PDFWriter是一个易于使用的C创建、修改PDF文档的库 1.创建一个PDF文件 #include #include “PDFWriter.h” int main() { std::cout << “Hello World!\n”; PDFWriter pdfWriter; int retpdfWriter.StartPDF(“D:\mytestwriterpdf.pdf”, ePDFVersion13); if (ret eS…

C++面向对象编程(2)

目录 一. 问题引入 二. 右值引用 1. lvalue/rvalue/prvalue/xvalue 1.1 表达式与对象的概念 1.2 左值与右值 2. moving semantics 2.1 显示绑定 2.2 Move constructors 2.3 Move assignment operator 2.4 实例分析 // TODO Quiz REF 本章简单介绍下move语义的“来…

day03_注释丶关键字丶标识符丶常量

​注释 注释就是使用人类的自然语言对代码的解释和说明。 代码本身和人类的自然语言相比&#xff0c;可读性肯定是要差一些&#xff0c;所以为了更快能够知道代码的含义、作用、需要注意地方&#xff0c;所有程序员都应该养成写注释的好习惯。 由于注释的内容是给程序员看的&…

《HelloGitHub》第 89 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对编程感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 https://github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 …

融合正余弦和柯西变异的麻雀搜索算法(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Error running ‘Tomcat 8.5.29‘ Address localhost:1099 is already in use

一、Error running ‘Tomcat 8.5.29’ Address localhost:1099 is already in use 原因&#xff1a;端口1099被占用了。 二、解决 2.1 解决方法一-结束该端口1099占用 //1-查看端口占用&#xff0c;根据端口号1099&#xff0c;获取PID(进程ID) netstat -ano | findstr "…

stackoverflow问题

Stack Overflow requires external JavaScript from another domain, which is blocked or failed to load. stackoverflow引用了谷歌中被屏ajax.googleapis.com的jquery.min.js文件。“https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js” 方案1.打开网站…

字节一面:你能讲一下跨域吗

前言 最近博主在字节面试中遇到这样一个面试题&#xff0c;这个问题也是前端面试的高频问题&#xff0c;作为一名前端开发工程师&#xff0c;我们日常开发中与后端联调时一定会遇到跨域的问题&#xff0c;只有处理好了跨域才能够与后端交互完成需求&#xff0c;所以深入学习跨域…

docker 04.更加重要的命令

之前的都是基础命令&#xff0c; 前台交互进程和后台守护进程&#xff1a; 重新进入容器&#xff1a; docker中的导入导出&#xff1a; docker中的拷贝到&#xff1a;

ubuntu学习(五)----读取文件以及光标的移动

1、读取文件函数原型介绍 ssize_t read(int fd,void*buf,size_t count) 参数说明&#xff1a; fd: 是文件描述符 buf:为读出数据的缓冲区&#xff1b; count: 为每次读取的字节数&#xff08;是请求读取的字节数&#xff0c;读上来的数据保存在缓冲区buf中&#xff0c;同时文…

ubuntu学习(四)----文件写入操作编程

1、write函数的详解 ssize_t write(int fd,const void*buf,size_t count); 参数说明&#xff1a; fd:是文件描述符&#xff08;write所对应的是写&#xff0c;即就是1&#xff09; buf:通常是一个字符串&#xff0c;需要写入的字符串 count&#xff1a;是每次写入的字节数…

小程序input的placeholder不垂直居中的问题解决

input的placeholder不垂直居中&#xff0c;input设置高度后&#xff0c;使用line-height只能使输入的文字垂直居中&#xff0c;但是placeholder不会居中&#xff0c;反而会偏上。 首先placeholder样式自定义 有两种方法&#xff0c;第一种行内样式&#xff1a; <input ty…

sql server 备份到网络共享

场景&#xff1a;sql server服务器A将数据库备份文件备份到服务器B 1&#xff09;服务器B创建共享目录 这里我将 D:\ProDbBak 共享&#xff0c;并且Everyone完全控制 2&#xff09;sql server服务器A能够访问服务器B共享目录&#xff0c;并且能完全控制 3&#xff09;修改服务…