C++学习-入门到精通-【5】类模板array和vector、异常捕获

C++教程之array 上一篇文章我们介绍了C++中的迭代器,这篇文章将会介绍C++中数组的概念,数组是一种和vector类似的数据结构,但是其在性能和灵活性上的权衡中选择了性能而放弃了一定的灵活性,其与vector相同的地方是,它们都是同一类型的对象的容器,也都可以通过下标访问。其不同点是数组的大小是固定的,所以无法向一个数组添加元素,也正是因为其大小固定,所以其在运行时有更好的性能。需要注意的是一些编译器是不支持数组的拷贝,如果直接通过一个数组去初始化另一个数组可能会报错。在理解声明时可以按照从左到右,从内到外的顺序。 阅读详情

C++学习-入门到精通-【5】类模板array和vector、异常捕获



一、array对象

Array是C++标准库中的类模板。array对象是一组具有相同类型的、连续的内存空间。每个array对象都知道自己的大小,可以调用类的成员函数size来确定。例如一个array对象c,使用c.size()可以获得c的大小。

array对象的声明

使用如下的语法声明一个array对象:
array <类型, 大小> array对象名;

// 声明一个元素类型为int的,大小为5的array对象
array <int, 5> arr;

尖括号对<>表明了array是一个类模板。编译器将根据元素的类型和array对象的大小来分配合适的内存空间(一个分配内存的声明,它的更合适的叫法应该是定义)。array对象的大小必须是一个无符号整型。

使用array对象的例子

#include <array>
#include <iostream>
#include <iomanip>

using namespace std;

int main()
{
	array<int, 5> arr1;
	static array<int, 10> arr;

	cout << setw(7) << "Element" << setw(13) << "Values" << endl;

	for (int i = 0; i < 5; i++)
	{
		cout << setw(5) << "arr1[" << i << "]" << setw(13) << arr1[i] << endl;
	}

	cout << "\n";

	for (int i = 0; i < 10; i++)
	{
		cout << setw(5) << "arr[" << i << "]" << setw(13) << arr[i] << endl;

	}
}

运行结果:
在这里插入图片描述

从结果中看,自动的array对象并不会隐式的初始化为0,静态的array对象会隐式的初始化为0。静态的array对象与静态的局部变量一样,只会在函数第一次调用时进行初始化,之后直到程序结束才会销毁。

使用初始化列表初始化array对象

在array对象的声明中,也可以对其元素进行初始化。具体做法是:在array对象名称的后面加一个等号和一个用逗号分隔的初始化列表,该列表用花括号括起来。

例如:

array <int, 5> a = {};

如果初始化列表中的值的个数小于array对象中元素的个数,那么剩下的对象元素都被初始化为0。上面的例子中,初始化列表中值的个数比array对象中元素的个数少(实际上一个值也没有),所以将没有对应值的元素初始化为0。
注:此方法只能在声明时使用

如果要在非声明的地方初始化array对象的元素,可以使用一个循环语句。

提示:
如果在一个array对象的声明中指定了array对象大小和初始化列表,那么初始化值的个数必须小于或等于array对象的大小。

下面的array对象声明语句就会引起编译错误:

array <int, 5> = { 1,2,3,4,5,6 } // error

使用常量变量指定array对象的大小

在C语言中,使用下面的语句是不被允许的:

const int i = 5;
int arr[i] = { 1,2,3,4,5 }; // error

在C语言中声明一个数组,数组的元素个数必须是一个常量。使用const修饰的变量虽然使用上具有常量的性质(初始化之后无法被修改,但是其本质上仍是一个变量)。

在C++中我们就可以使用常量变量来指定一个array对象的大小,比如:

const int a = 5;
array <int, i> arr = { 1,2,3,4,5 };

但是绝对不能使用变量作为array对象的大小;
在这里插入图片描述

注意:使用常量变量时,必须在声明它的时候进行初始化
在这里插入图片描述

二、基于范围的for语句

这是一个C++11的新特性,该语句允许程序员不使用计数器就可以完成所有元素的编历,从而避免array缓冲区溢出的可能性,且减少了程序员的工作量(不需要他们自己去实现对边界的检查功能)。

提示:当处理array对象的所有元素时,如果没有访问array对象元素下标的需求,那么使用基于范围的for语句可以较大程度上预防错误的发生

基于范围的for语句的语法形式:

for(范围变量声明 : 表达式)
	语句

其中范围变量声明中必须包含一个类型名称和一个标识符(例如:int item),表达式是需要迭代遍历的array对象。范围变量声明中的类型必须与array对象的元素类型相一致,而标识符代表循环的连续迭代中下一个array对象的值。

下面给出一个使用基于范围的for语句的例子。

#include <iostream>
#include <array>

using namespace std;

int main()
{
	array <int, 5> items = { 1,2,3,4,5 };
	
	cout << "items before modification: ";
	for (int item : items)
	{
		cout << item << " ";
	}

	for (int item : items)
	{
		item *= 2;
	}

	cout << "\nitems after modification(non-reference): ";
	for (int item : items)
	{
		cout << item << " ";
	}

	for (int& item : items)
	{
		item *= 2;
	}

	cout << "\nitems after modification(reference): ";
	for (int item : items)
	{
		cout << item << " ";
	}
}

运行结果:
在这里插入图片描述

可以看到在这种基于范围的for语句中,使用的标识符是array对象的一个副本,对它进行修改并不会对array对象本身的值产生影响。所以这里需要使用引用,来实现对array对象值的修改。

注意:要使用基于范围的for语句,循环对象必须要有begin函数(它是什么我们会在迭代器章节介绍)

三、利用array对象存放成绩的GradeBook类

GradeBook.h

#include <string>
#include <array>

class GradeBook
{
public:
	static const size_t students = 10; // 测试数据,学生人数

	GradeBook(const std::string &, const std::array<int, students> &);
	void displayMessage() const;
	void setCourseName(const std::string &);
	std::string getCourseName() const;
	//auto getCourseName() const -> std::string; 
	// 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型
	void processGrades() const;
	int getMaximum() const;
	int getMinimum() const;
	double getAverage() const;
	void outputBarChart() const;
	void outputGrades() const;

private:
	std::string CourseName;
	std::array<int, students> grades; // 保存学生的成绩
};

GradeBook.cpp

#include "GradeBook.h"
#include <iostream>
#include <iomanip>

using namespace std;

// 构造函数
GradeBook::GradeBook(const string& name, 
	const array<int, students>& gradeArray)
	// or const array<int, GradeBook::students>& gradeArray) 
	// 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员
	// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员
	: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}

// 打印欢迎信息
void GradeBook::displayMessage() const
{
	cout << "Welcome to the Grade Book for\n" 
		<< getCourseName() << "!" << endl;
}

// set成员函数
void GradeBook::setCourseName(const string& name)
{
	CourseName = name;
}

// get成员函数
string GradeBook::getCourseName() const
{
	return CourseName;
}

// 对成绩进行多种操作
void GradeBook::processGrades() const
{
	// 打印成绩
	outputGrades();

	// 打印班级平均成绩
	cout << setprecision(2) << fixed; // 打印浮点数后面两位,不足补0
	cout << "\nClass Average is " << getAverage() << endl;

	// 打印最低成绩和最高成绩
	cout << "Lowest grade is " << getMinimum() << endl
		<< "Highest grade is " << getMaximum() << endl;

	// 打印班级成绩分布条形图
	outputBarChart();
}

int GradeBook::getMaximum() const
{
	int max = 0; // 成绩是一个非负数,将最大值初始化为0

	// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句
	// 表达式是要循环的对象,也就是数据成员grades
	for (int grade : grades)
	{
		if (grade > max)
		{
			max = grade;
		}
	}

	return max;
}

int GradeBook::getMinimum() const
{
	int min = 100; // 成绩最大值为100,将最小值初始化为100

	// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句
	for (int grade : grades)
	{
		if (grade < min)
		{
			min = grade;
		}
	}

	return min;
}

double GradeBook::getAverage() const
{
	int total = 0;

	for (int grade : grades)
	{
		total += grade;
	}

	return (static_cast<double>(total) / students);
	// or return (static_cast<double>(total) / grades.size());
	// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数
	// 该值与使用类模板创建一个array对象时的第二个参数相同
}

void GradeBook::outputBarChart() const
{
	cout << "\nGrade distribution:" << endl;

	// 将成绩分成11个区间
	// 0-9
	// 10-19
	// 20-29
	// 30-39
	// ...
	// 90-99
	// 100

	const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护
	array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0
		// 用以保存每个区间中学生的人数
	// 遍历成绩数组,获取每个区间的人数
	for (int grade : grades)
	{
		frequency[grade / 10]++;
	}

	// 打印条形图
	for (int i = 0; i < frequencySize; i++)
	{
		// 打印表头
		if(i != 10)
			cout << setw(2) << i * 10 << " - " 
			<< setw(3) << 9 + i * 10 << ": ";
		else
			cout << setw(10) << "100: ";

		// 打印符号*,表示一个人
		for (int stars = 0; stars < frequency[i]; stars++)
		{
			cout << "*";
		}
		cout << endl;
	}
}

// 打印学生的成绩
void GradeBook::outputGrades() const
{
	cout << "\nThe grades are: \n";

	for (int student = 1; student <= grades.size(); student++)
	{
		cout << "student" << setw(2) << student << ":" 
			<< setw(3) << grades[student - 1] << endl;
	}
}

test.cpp

#include "GradeBook.h"

using namespace std;

int main()
{
	// 学生成绩
	array<int, GradeBook::students> grades = 
	{ 87,68,94,100,88,92,78,67,83,98 };

	// 课程名
	string CourseName = "CS1201 C++ Programming";

	// 创建一个GradeBook对象
	GradeBook myGradeBook(CourseName, grades);

	myGradeBook.displayMessage();
	myGradeBook.processGrades();
}

运行结果:
在这里插入图片描述

其中使用了array类中的一个成员函数:

在这里插入图片描述

注意:类中定义的static的数据成员是所有成员共有的,有const的static数据成员可以在类定义时就初始化,没有const的数据成员必须在类外进行初始化。并不像普通的数据成员一样每一个对象都有一个副本

四、array对象的排序与查找

排序
在这里插入图片描述
查找
在这里插入图片描述

使用排序和查找的例子

在介绍示例之前我们先看一段代码:

#include <string>
#include <iostream>

using namespace std;

int main()
{
	string s1 = "abcf";
	string s2 = "abcd";

	if (s1 < s2)
	{
		cout << "s1 < s2" << endl;
	}
	else
	{
		cout << "s1 >= s2" << endl;
	}
}

这段代码在C语言中是不可行的,因为关系运算符是无法比较字符串的大小的,但是C++中引入了运算符重载的概念(后面会介绍),所以string对象的大小可以使用关系运算符进行比较。

#include <iostream>
#include <algorithm>
#include <array>
using namespace std;

int main()
{
	array<int, 5> a = { 5,4,2,3,1 };

	cout << "Before sort:" << endl;
	for (int i : a)
	{
		cout << i << " ";
	}

	sort(a.begin(), a.end());

	cout << "\n\nAfter sort:" << endl;
	for (int i : a)
	{
		cout << i << " ";
	}
}

运行结果:
在这里插入图片描述

上面传递给sort函数模板的参数类型如下:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

关于begin和end两个函数,我们会在后续介绍迭代器的章节详细说明。

另一个例子:

#include <iostream>
#include <string>
#include <array>
#include <algorithm>

using namespace std;

int main()
{
	const int arraySize = 7;
	array <string, arraySize> colors = { "red", "yellow", "blue", 
		"green", "orange", "indigo", "violet"};

	cout << "Unsorted array:" << endl;
	for (string item : colors)
	{
		cout << item << " ";
	}

	sort(colors.begin(), colors.end());

	cout << "\n\nSorted array:" << endl;
	for (string item : colors)
	{
		cout << item << " ";
	}

	bool found = binary_search(colors.begin(), colors.end(), "indigo");
	cout << "\n\n\"indigo\"" << (found? " was " : " was not ")
		<< "found in colors." << endl;

	found = binary_search(colors.begin(), colors.end(), "cyan");
	cout << "\n\n\"cyan\"" << (found ? " was " : " was not ")
		<< "found in colors." << endl;
}

运行结果:

在这里插入图片描述
注意:要利用binary_search函数确定一个值是否在array对象中,前提是该array对象中的值是升序排序好的。该函数并不会检查array对象是否已排序

五、多维array对象

多维的array对象是通过嵌套语句的形式进行声明的。例如:

#include <array>
using namespace std;
// 声明一个二维array对象
array<array<int, 4>, 3> arr = {}; // 所有值初始化为0
const int rows = 2;
const int columns = 3;
array<array<int, columns>, rows> arr2 = { 1,2,3,4,5 }; 

上面代码定义了一个3行4列的二维array对象,初始化为0。
arr是一个array对象(有3个元素),它的元素的类型也是一个array对象(有4个int类型的元素)。

二维array对象的使用——嵌套的基于范围的for语句

for (const auto& row : arr2)
{
	for (auto const& column : row)
	{
		// operation
	}
}

上面的for语句中,使用auto关键字作为变量的类型,它的含义是让编译器根据该变量初始化值来确定它的数据类型。

六、利用二维array对象的GradeBook类

在上面的GradeBook类的代码中,我们只有一个一维的array对象用来保存成绩,但是一个学期不可能只有一次考试,所以这显然是不够的。

假设一个学期进行4次考试:当前班级中有10个学生,所以我们需要一个10x4的array对象来保存这些数据。

GradeBook.h

#include <string>
#include <array>

class GradeBook
{
public:
	static const size_t students = 10; // 测试数据,学生人数
	static const size_t tests = 4;

	GradeBook(const std::string&, const std::array<std::array<int, tests>, students>&);
	void displayMessage() const;
	void setCourseName(const std::string&);
	std::string getCourseName() const;
	//auto getCourseName() const -> std::string; 
	// 使用之前提到的尾随返回值类型的语法声明get成员函数的返回值类型
	void processGrades() const;
	int getMaximum() const;
	int getMinimum() const;
	double getAverage(const std::array<int, tests> &) const;
	void outputBarChart() const;
	void outputGrades() const;

private:
	std::string CourseName;
	std::array<std::array<int, tests>, students> grades; // 保存学生的成绩
};

GradeBook.cpp

#include "GradeBook.h"
#include <iostream>
#include <iomanip>

using namespace std;

GradeBook::GradeBook(const string& name,
	const array<array<int, tests>, students>& gradeArray)
	// const array<int, GradeBook::students>& gradeArray) 
	// 在这里不需要使用(类名::数据成员)这样的语法来使用这个数据成员
	// 因为构造也是类的成员函数,成员函数的作用域中可以直接使用类中的公开数据成员
	: CourseName(name), grades(gradeArray) // 使用初始化列表初始化两个数据成员
{
}

// 打印欢迎信息
void GradeBook::displayMessage() const
{
	cout << "Welcome to the Grade Book for\n" 
		<< getCourseName() << "!" << endl;
}

// set成员函数
void GradeBook::setCourseName(const string& name)
{
	CourseName = name;
}

// get成员函数
string GradeBook::getCourseName() const
{
	return CourseName;
}

// 对成绩进行多种操作
void GradeBook::processGrades() const
{
	// 打印成绩
	outputGrades();

	// 打印最低成绩和最高成绩
	cout << "Lowest grade is " << getMinimum() << endl
		<< "Highest grade is " << getMaximum() << endl;

	// 打印班级成绩分布条形图
	outputBarChart();
}

int GradeBook::getMaximum() const
{
	int max = 0; // 成绩是一个非负数,将最大值初始化为0

	// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句
	// 表达式是要循环的对象,也就是数据成员grades
	for (auto const& student : grades) // 使用引用,减少复制副本的开销
	{
		for (auto const& grade : student)
		{
			if (grade > max)
			{
				max = grade;
			}
		}
	}

	return max;
}

int GradeBook::getMinimum() const
{
	int min = 100; // 成绩最大值为100,将最小值初始化为100

	// 不需要考虑数组的下标,只需要遍历数组的每个元素,使用基于范围的for语句
	for (auto const& student : grades) // 使用引用,减少复制副本的开销
	{
		for (auto const& grade : student)
		{
			if (grade < min)
			{
				min = grade;
			}
		}
	}

	return min;
}

double GradeBook::getAverage(const array<int, tests>& setOfGrades) const
{
	int total = 0;

	// 计算一个学生一学期的平均成绩
	for (auto const& grade : setOfGrades)
	{
		total += grade;
	}

	return (static_cast<double>(total) / tests);
	// or return (static_cast<double>(total) / setOfGrades.size());
	// 可以使用array类中提供的成员函数size()来获取array对象中元素的个数
	// 该值与使用类模板创建一个array对象时的第二个参数相同
}

void GradeBook::outputBarChart() const
{
	cout << "\nGrade distribution:" << endl;

	// 将成绩分成11个区间
	// 0-9
	// 10-19
	// 20-29
	// 30-39
	// ...
	// 90-99
	// 100

	const int frequencySize = 11; // 用一个变量来保存区间数,方便代码的维护
	array<int, frequencySize> frequency = {}; // 将一个有11个元素的array对象初始化为全0
		// 用以保存每个区间中学生的人数
	// 遍历成绩数组,获取每个区间的人数
	for (auto const& student : grades) // 使用引用,减少复制副本的开销
	{
		for (auto const& grade : student)
		{
			frequency[grade / 10]++;
		}
	}

	// 打印条形图
	for (int i = 0; i < frequencySize; i++)
	{
		// 打印表头
		if(i != 10)
			cout << setw(2) << i * 10 << " - " 
			<< setw(3) << 9 + i * 10 << ": ";
		else
			cout << setw(10) << "100: ";

		// 打印符号*,表示一个人
		for (int stars = 0; stars < frequency[i]; stars++)
		{
			cout << "*";
		}
		cout << endl;
	}
}

// 打印学生的成绩
void GradeBook::outputGrades() const
{
	cout << "\nThe grades are: \n";
	cout << setw(10) << " "; // 打印表头,对应student id

	for (int i = 0; i < tests; i++)
	{
		cout << setw(5) << "Test" << setw(2) << i + 1;
	}

	cout << setw(9) << "Average" << endl;

	// 输出所有学生的成绩
	for (int student = 1; student <= grades.size(); student++)
	{
		cout << "student" << setw(2) << student << ":" ;

		// 输出一个学生的所有成绩
		for (int test = 0; test < tests; test++)
		{
			cout << setw(7) << grades[student - 1][test];
		}
		// 输出该学生的平均成绩
		cout << setprecision(2) << fixed << setw(9) << getAverage(grades[student - 1]) << endl;
	}
}

test.cpp

#include "GradeBook.h"

using namespace std;

int main()
{
	// 学生成绩
	array<array<int, GradeBook::tests>, GradeBook::students> grades = 
	{
		87,  96,  70,  97,
		68,  87,  90,  93,
		94, 100,  90,  98,
	   100,  82,  81,  92,
		83,  65,  83,  80,
		78,  87,  65,  81,
		67,  78,  85,  90,
		77,  79,  63,  88,
		99, 100,  95,  96,
		85,  83,  79,  90
	};

	// 课程名
	string CourseName = "CS1201 C++ Programming";

	// 创建一个GradeBook对象
	GradeBook myGradeBook(CourseName, grades);

	myGradeBook.displayMessage();
	myGradeBook.processGrades();
}

运行结果:

在这里插入图片描述

七、C++标准库类模板vector的介绍

vector对象的声明语法:
vertor<类型> 名称(大小);

示例代码

#include <iostream>
#include <vector>

using namespace std;

void outputVector(const vector<int> &);
void inputVector(vector<int> &);

int main()
{
	// 与array类模板的声明类似,在<>中指定保存元素的类型,但是容量在变量名后指定
	vector<int> integer1(7); // 创建一个有7个int类型元素的vector对象
	vector<int> integer2(10); // 创建一个有7个int类型元素的vector对象

	// 输出两个vector对象的大小及默认初始值
	cout << "\nSize of vector integer1 is " << integer1.size() << endl
		<< "vector after initialization:";
	outputVector(integer1);
	cout << "\nSize of vector integer2 is " << integer2.size() << endl
		<< "vector after initialization:";
	outputVector(integer2);

	// 输出17个整数用于初始化两个vector对象
	cout << "Enter 17 ingeters:" << endl;
	inputVector(integer1);
	inputVector(integer2);

	// 输出赋值后的vector对象的值
	cout << "\nAfter input, the vectors contain:\n"
		<< "integer1:" << endl;
	outputVector(integer1);
	cout << "integer2:" << endl;
	outputVector(integer2);

	cout << "\nEvaluation: integer1 != integer2" << endl;
	if (integer1 != integer2)
	{
		cout << "integer1 and integer2 are not equal" << endl;
	}

	// 创建一个新vector对象,并使用integer1赋值
	vector<int> integer3(integer1);
	cout << "\nSize of vector integer3 is " << integer3.size() << endl
		<< "vector after initialization:";
	outputVector(integer3);

	// 对vector对象直接使用'='进行赋值
	cout << "\nAssigning integer2 to integer1: " << endl;
	integer1 = integer2;

	cout << "integer1:" << endl;
	outputVector(integer1);
	cout << "integer2:" << endl;
	outputVector(integer2);

	cout << "\nEvaluation: integer1 == integer2" << endl;
	if (integer1 == integer2)
	{
		cout << "integer1 and integer2 are equal" << endl;
	}

	cout << "\ninteger1[5] is " << integer1[5] << endl;

	cout << "\n\nAssigning 1000 to integer1[5]." << endl;
	integer1[5] = 1000;
	cout << "integer1:" << endl;
	outputVector(integer1);

	// 异常处理,访问越界
	try {
		cout << "\n\nAttempt to display integer1.at(15)." << endl;
		cout << integer1.at(15) << endl; // error,越界
	}
	catch (out_of_range &ex){
		cerr << "An exception occured: " << ex.what() << endl;
	}

	cout << "\nCurrent Size of integer3 is " << integer3.size() << endl;
	integer3.push_back(1000); // 在integer3的末尾添加一个元素3
	cout << "New integer3 size is " << integer3.size() << endl;
	cout << "integer3 now contains: " << endl;
	outputVector(integer3);
}

void outputVector(const vector<int>& array)
{
	// 使用基于范围的for语句遍历整个vector对象
	for (int item : array)
	{
		cout << item << "  ";
	}

	cout << endl;
}

void inputVector(vector<int>& array)
{
	for (int item : array)
	{
		cin >> item;
	}
}

运行结果:

在这里插入图片描述

代码中使用的库函数:

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

从上面的程序执行结果可以看出,vector对象可以使用关系运算符进行比较操作。

一个vector对象可以用另一个vector对象进行初始化。也可以使用一个vector对象为另一个vector对象赋值。

还可以像数组一样使用[]和下标来访问指定的vector元素,但是在使用[]进行访问时,C++是不会进行边界检查的。但是在vector类提供的at函数中,是提供了边界检验功能的。

异常处理:处理超出边界的下标

异常是一个在程序运行时出现的问题的表现。异常处理使程序员能够创建可以解决(或处理)异常的容错程序。在很多情况下,在处理异常的同时还允许程序继续运行,就像没有遇到异常一样。

try语句:
为了处理一个异常需要把可能抛出一个异常的任何代码放置在一个try语句中。

catch语句:
包含了发生异常时,负责处理异常的代码。

比如,上面例子中try语句中包含了一个调用vector类的at成员函数的语句,该函数提供了边界检查和抛出异常的功能,当这个函数的实参是一个无效下标时,就会抛出一个异常。在默认的情况下这会导致C++程序终止。在这里下标15显然不是一个有效的下标,所有异常出现,由该try语句对应的catch语句来处理这个异常。
从上面的库函数介绍图中,可以看出,at函数抛出的异常是out_of_range类型的异常。所以在上面代码的catch语句指定了处理的异常的类型为out_of_range,且声明了一个用于接收引用的异常形参ex。在这个语句块中,可以使用形参的标识符来实现与捕捉到的异常对象的交互。

注意,try和catch是两个不同的语句块,它们的作用域不同,在try中声明的变量无法在catch中使用。

异常形参的what函数:
在上面的代码中调用了这个异常对象的what成员函数,来得到并显示存储在此异常对象中的错误信息。

更详细的异常处理内容会在之后的章节中说明。

vector对象和array对象的主要区别

vector对象和array对象的一个主要区别就是vector对象可以动态增长以容纳更多元素。

使用成员函数push_back可以为vector对象增加一个元素,对应的可以使用pop_back这个成员函数删除vector对象中的一个元素。

除了像上面一样使用for循环语句对vector对象进行初始化,还可以使用初始化列表对vector对象进行初始化。例如:

#include <iostream>
#include <vector>

using namespace std;

int main()
{
	vector<int> integer4 = { 1,2,3,4,5 };
	// or vector<int> integer4{1,2,3,4,5};
	for (int item : integer4)
	{
		cout << item << "  ";
	}
}

上面这段代码中,使用初始化列表将vector对象integer4初始化为有5个元素vector对象。

别光看原理图了!手把手教你用Altium Designer搞定STM32F411最小系统的PCB布局(附电源/晶振/复位电路实战) 本文详细介绍了使用Altium Designer进行STM32F411最小系统PCB布局的实战技巧,涵盖电源分配网络优化、高速信号布线及系统级布局策略。通过规范的工程结构建立、关键设计规则预设和核心电路模块布局,帮助工程师提升PCB设计效率与信号完整性。特别针对STM32最小系统的电源、晶振和复位电路提供了专业解决方案。 阅读详情

相关推荐

PBR:双向反射分布函数(BRDF)介绍与Cook-Torrance模型的实现

PBR:双向反射分布函数(BRDF)介绍与Cook-Torrance模型的实现 BRDF简介 再介绍BRDF之前我们要引入渲染方程这个东西: 其中L表示辐射率,其公式为: 它表示了一个拥有辐射强度Φ的光源在单位面积A,单位立体角ω上的辐射出的总能量。 辐射率是辐射度量学上表示一个区域平面上光线总量的物理量,它受到入射光线与平面法线间的夹角θ的余弦值cosθ的影响:当直接...

小龙虾的博客 1万+

【STL】C++ STL之array详解

c++ STL之array详解

行码棋 2万+

海康读码器上位机开发避坑指南:IDMVS客户端之外,如何用C# SDK搞定扫码、数据比对与实时控制?

本文详细介绍了如何利用海康读码器的C# SDK进行二次开发,实现从基础扫码到复杂工业控制的全流程解决方案。内容涵盖SDK架构解析、多设备管理系统构建、业务逻辑与设备控制实现,以及系统集成与性能优化等关键环节,为工业自动化领域的开发者提供实用指南。

weixin_30642561的博客 550

array详解

array详细介绍

m0_59666413的博客 4929

什么是plm系统?-数字化转型网

当今世界,产品研发能力是企业在激烈的市场竞争中保持战略优势的核心竞争力之一。如何有效地缩短产品研发周期、改善产品服务的设计迭代流程、有效降低产品的研发成本,也是企业面临的主要问题之一。PLM(Product Lifecycle Management,产品生命周期管理)在优化产品研发的全管理流程、增强企业产品的市场竞争力方面具有关键的作用。

cxo17757154043的博客 882

MS2107 CVBS转USB2.0 音视频采集芯片,支持1080P@30HZ输出

MS2107 是一款视频和音频采集芯片,支持CVBS转USB2.0 ;可以将 CVBS、S-Video 和音频信号通过 USB接口传送到 PC、智能手机和平板电脑上预览或采集。

TEL18967112838的博客 2075

C++数据结构——array、vector、链表

一、 array模板类 C++中的数组类型是继承了c语言的特性,在使用数组的时候要注意数组越界操作问题。为了更安全的对数组进行操作,C++提出了数组模板类array。array内存空间为连续的一段地址,适用于提前已知所要存储的数据类型和数量、进行大量的查、改操作,不适用于含有大量交换、删除、增加数据的操作,该容器无法动态改变大小,所以说提前已知存储数据类型和数量。 1、array模板...

知识搬运工的博客 6625

STC15W204S最小系统开发指南:从串口通讯到自动热加载全流程

本文详细介绍了STC15W204S最小系统的完整开发流程。从芯片资源解析、最小系统搭建、串口通讯驱动编写(使用Timer2生成波特率),到实现基于魔术值触发的自动热加载功能,并最终集成Keil与STC-ISP软件,构建高效的自动化开发工作流,显著提升嵌入式调试效率。

a1b2c的博客 391

C++ array函数

c++ STL

weixin_59141600的博客 1万+

把 OData V4 服务真正发布出去:事务码 /IWFND/V4_ADMIN 在 SAP S/4HANA On-Premise 里的定位与用法

本文介绍了SAP S/4HANA中的事务码/IWFND/V4_ADMIN,这是SAP Gateway管理OData V4服务的关键工具。该事务码主要负责将后端注册的OData V4服务以服务组形式发布到前端,并维护系统别名路由、测试入口和日志跳转。与OData V2不同,V4采用服务组概念以支持跨服务导航,类似商场统一管理多个专柜。文章还通过实际案例说明,未发布服务组会导致BAS等工具无法发现OData V4服务,并提供了验证服务组状态的访问路径和ABAP示例代码。

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 207

5.30华为OD机试真题 新系统 - 链表数字游戏 (Java/Py/C/C++/Js/Go)

5.30华为OD机试真题 新系统 - 链表数字游戏 (Java/Py/C/C++/Js/Go)

算法大师! 1116

《C++大学教程》 第7章 类模板array和vector、异常捕获 笔记

第七章在学校就已看完,但是临放假比较忙。作为年前的第十篇,也没有完成上一年的任务,唉~ 附上的自己敲的代码,第一次加上了注释。 最近在思考,作为一个非机专业出身的人,编程到底要学多少,学到什么程度,才能算一个合格的控制硕士? 是只需要仿真数据处理? 还是别的什么? 求解答疑惑…… 新年第一更,大家过年好~

战死为止的博客 749

对halcon形状匹配算法的一点分析

基于Intel VTune Profiler对halcon形状匹配算法的一点分析

manuoo的专栏 567

C++重学之路 7 类模板array和vector、异常捕获

7 类模板array和vector、异常捕获1 array对象2 array对象的声明3 使用array对象的例子3.1 声明array对象以及用循环来初始化array对象的元素3.2 在声明中用初始化列表初始化array对象3.3 用常量变量指定array对象的大小3.4 array对象下标的边界检查3.5 静态局部array对象和自动局部array对象3.6 基于范围的for语句4 array对象的排序和查找排序查找示范说明5 多维array对象6 C++标准库类模板vector的介绍创建vector对

m0_59751822的博客 632

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

认识、使用C++vector和array

简单了解C++数组替代品,vector和array。

muwithxi的博客 1517

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

vector和array在C++中的区别以及如何在C++中定义array类型

的访问效率很高,因为它是连续的内存空间,可以直接通过下标访问。数组的大小必须在编译时确定,并且数组不能存储其定义之外的数据。在插入或删除元素时,迭代器可能会失效(指向的内存位置可能发生变化),除非是在尾部进行添加或删除操作。也可以存储任何类型的元素,但类型必须在编译时确定,并且所有元素必须具有相同的数据类型。的迭代器(实际上是指针)在数组生命周期内是稳定的,因为它们总是指向固定的内存位置。的大小是固定的,并且必须在编译时确定。在定义时必须初始化或指定大小,并且一旦定义,其大小就不能改变。

2402_85246552的博客 1514

07 chapter 类模板array和vector、异常捕获(cpp大学教程)学习笔记

7.1 array对象 7.1.1 声明 array<type, size> name; 用常量变量声明array对象 const size_t arraySize = xx; array<type, arraySize> name; 常量变量(命名常量或者只读变量)必须用常量表达式初始化 7.1.2 array初始化 使用for循环初始化 for(size_t i = 0; i < array1.size(); i++){arr

stay_alive001的博客 499

C++类模板实战:从零实现通用Array容器,掌握泛型编程核心

泛型编程是现代C++的核心范式之一,它通过参数化类型实现了代码的高度复用。其基本原理是在编译期生成特定类型的代码,这种编译期多态避免了运行时开销。类模板作为泛型编程的关键技术,能够定义可操作任意数据类型的通用容器或算法,极大提升了代码的抽象能力和可维护性。在实际工程中,类模板广泛应用于标准库容器(如vector、map)、算法以及自定义数据结构的实现。本文以动态数组Array为例,深入解析类模板的设计与实现,涵盖深拷贝、动态扩容、迭代器等核心机制,并探讨移动语义、异常安全等高级话题,帮助开发者从原理到实践全

weixin_30252709的博客 341

C++基础:STL序列式容器:list、array、vector、queue、deque

这篇是不得不写,因为很重要,需要做总结。 主要写STL容器 1.list容器 可以参考:list容器 list容器是个双向链表容器,前后元素靠指针维系,所以list容器中的元素可以分散存储在内存空间,而不是必须存储到连续内存。 这样的存储结构,在序列的任何已知位置插入或删除元素很方便快速,时间复杂度为O(1)O(1)O(1),但是不可以通过位置访问元素。比如array和vector可以直接支持容器对象名[n]来访问第n个元素,list不支持。 使用容器时,请包含代码: #include <list&g

AndyJ的学习放弃之旅 1249

c++ vector和array的区别

C++ 中的 vector 和 array 是两种常见的容器类型,它们的主要区别如下:

weixin_45372314的博客 579

C++类模板封装容器:从vector扩展到可控泛型编程

容器封装是C++泛型编程的核心实践,本质是通过类模板实现接口抽象与策略注入。其原理在于利用模板参数化类型、分配器和行为契约,在编译期建立强类型约束与零开销抽象。技术价值体现在可扩展性(如审计日志、内存池集成)、可控性(线程安全粒度、异常语义定制)和工程健壮性(规避继承陷阱、保障析构安全)。典型应用场景包括高性能中间件开发、金融系统容器增强、嵌入式内存受限环境定制,以及C++中高级岗位面试中的vector手写考察。本文以MyVector为范例,深入解析组合式封装、迭代器重写与SFINAE约束等关键实现。

weixin_30616969的博客 324

C++ STL系列-03.vector,array

需要动态大小使用vector,大小在编译时已知且固定时用 array(它比 C 风格数组更安全,提供了size()、边界检查at()等)。

qq_41424688的博客 423

C++中原生数组、STL的vector、STL的array的区别_data-&gt;at(n)

一个新插入元素位置的迭代器。下面的例子,演示了如何使用 insert() 函数向 vector 容器中插入元素。#include#include#includeint main()//第一种格式用法//{1,3,2}//第二种格式用法//第三种格式用法//第四种格式用法i++) {return 0;运行结果为:

2401_84240431的博客 1125

C++ STL容器——序列式容器(array、vector、deque、list)

概述 1.C++ STL的容器分为三种,序列式容器,关联式容器,无序式容器,这里先说说常用的序列式容器。 2.array,vector,deque,list,forward_list这几种都是序列式容器,序列容器是以线性序列的方式存储元素,也就是说,在内存,是连续分配一块内存来存放元素的,是可以经过标迭代的方式遍历元素。 3.C++的容器是不能用来装引用和函数的,容器的设计原则是以效率为,安全为次的,所以容器本身并不带有异常处理。 一.基本用法 所有的序列式容器都有一些共同的属性和用法,这里我拿最学常用的s

知来者逆的博客 1668

【小白学习C++ 教程】二十一、C++ 中的STL容器Arrays和vector

@Author:Runsen C++的标准模板库(STL)是提供数组、向量、队列等数据结构的模板类的集合。STL是由容器、算法、迭代器组成的库。 容器 容器存储对象和数据。它们基本上是基于模板的泛型类。 STL中的容器分为以下几种: 顺序容器 可以以顺序或线性方式访问的容器称为顺序容器。 Array, vector, queue, deque, list, map, set 是线性存储数据的 STL 容器,可以按顺序访问。 关联容器 关联容器是实现排序数据结构的容器。这些容器可以快速搜索。关联容器的

微信号:RunsenLiu 1281

vector和array的区别(含转过无数次的文章)

vector和array的区别 arrary的空间是由系统分配的,在编译时已经确定,存放在栈区 vector的空间可由程序员动态分配,可动态增长,在运行时才确定大小,存放在堆区 要想深入理解它们的区别,则就是堆和栈的区别 一、预备知识—程序的内存分配 一个由C/C++编译的程序占用的内存分为以下几个部分 1、栈区(stack)— 由编译器自动分配释放 ,存放函数的参数值,局部变量的

etwdone的专栏 1534

C++STL之vector动态数组

一、vector的简单使用以及耗时测试: #include<iostream> #include<vector> #include<cstdlib>//qsort bsearch NULL #include<ctime> using namespace std; const int SIZE = 100000; int main() { vecto...

KingOfMyHeart的博客 970
上一篇: C++学习-入门到精通-【4】函数与递归入门
下一篇: C++学习-骑士巡游问题
YKPG
博客等级 码龄6年 344粉丝 37原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值