C++学习笔记(18)

发布于:2024-09-18 ⋅ 阅读:(28) ⋅ 点赞:(0)

228、可变参数模板
可变参数模版是 C++11 新增的最强大的特性之一,它对参数进行了泛化,能支持任意个数、任意数
据类型的参数。
示例:
#include <iostream>
#include <thread>
using namespace std;
template <typename T>
void show(T girl) // 向超女表白的函数,参数可能是超女编号,也可能是姓名,所以用 T。
{
cout << "亲爱的" << girl << ",我是一只傻傻鸟。\n";
}
// 递归终止时调用的非模板函数,函数名要与展开参数包的递归函数模板相同。
void print()
{
cout << "递归终止。\n";
}
// 展开参数包的递归函数模板。
template <typename T, typename ...Args>
void print(T arg, Args... args)
{
//cout << "参数: " << arg << endl; // 显示本次展开的参数。
show(arg); // 把参数用于表白。
//cout << "还有" << sizeof...(args) << "个参数未展开。" << endl; // 显示未展开变参的个
数。
print(args...); // 继续展开参数。
}
template <typename...Args>
void func(const string& str, Args...args) // 除了可变参数,还可以有其它常规参数。
{
cout << str << endl; // 表白之前,喊句口号。
print(args...); // 展开可变参数包。
cout << "表白完成。\n";
}
int main(void)
{
//print("金莲", 4, "西施");
//print("冰冰", 8, "西施", 3);
func("我是绝世帅歌。", "冰冰", 8, "西施", 3); // "我是绝世帅歌。"不是可变参数,其它的都是。
}
229、时间操作 chrono 库
C++11 提供了 chrono 模版库,实现了一系列时间相关的操作(时间长度、系统时间和计时器)。
头文件:#include <chrono>
命名空间:std::chrono 一、时间长度
duration 模板类用于表示一段时间(时间长度、时钟周期),如:1 小时、8 分钟、5 秒。
duration 的定义如下:
template<class Rep, class Period = std::ratio<1, 1>>
class duration
{ ……
};
为了方便使用,定义了一些常用的时间长度,比如:时、分、秒、毫秒、微秒、纳秒,它们都位于 s
td::chrono 命名空间下,定义如下:
using hours = duration<Rep, std::ratio<3600>> // 小时
using minutes = duration<Rep, std::ratio<60>> // 分钟
using seconds = duration<Rep> // 秒
using milliseconds = duration<Rep, std::milli> // 毫秒
using microseconds = duration<Rep, std::micro> // 微秒
using nanoseconds = duration<Rep, std::nano> // 纳秒
注意:
 duration 模板类重载了各种算术运算符,用于操作 duration 对象。
 duration 模板类提供了 count()方法,获取 duration 对象的值。
示例:
#include <iostream>
#include <chrono> // chrono 库的头文件。
using namespace std;
int main()
{
chrono::hours t1(1); // 1 小时
chrono::minutes t2(60); // 60 分钟
chrono::seconds t3(60 * 60); // 60*60 秒
chrono::milliseconds t4(60 * 60 * 1000); // 60*60*1000 毫秒
chrono::microseconds t5(60 * 60 * 1000 * 1000); // 警告:整数溢出。
chrono::nanoseconds t6(60 * 60 * 1000 * 1000*1000); // 警告:整数溢出。
if (t1 == t2) cout << "t1==t2\n";
if (t1 == t3) cout << "t1==t3\n";
if (t1 == t4) cout << "t1==t4\n";
// 获取时钟周期的值,返回的是 int 整数。
cout << "t1=" << t1.count() << endl;
cout << "t2=" << t2.count() << endl;
cout << "t3=" << t3.count() << endl;
cout << "t4=" << t4.count() << endl;
chrono::seconds t7(1); // 1 秒
chrono::milliseconds t8(1000); // 1000 毫秒
chrono::microseconds t9(1000 * 1000); // 1000*1000 微秒
chrono::nanoseconds t10(1000 * 1000 * 1000); // 1000*1000*1000 纳秒
if (t7 == t8) cout << "t7==t8\n";
if (t7 == t9) cout << "t7==t9\n";
if (t7 == t10) cout << "t7==t10\n";
// 获取时钟周期的值。
cout << "t7=" << t7.count() << endl;
cout << "t8=" << t8.count() << endl;
cout << "t9=" << t9.count() << endl;
cout << "t10=" << t10.count() << endl;
}
二、系统时间
system_clock 类支持了对系统时钟的访问,提供了三个静态成员函数:
// 返回当前时间的时间点。
static std::chrono::time_point<std::chrono::system_clock> now() noexcept;
// 将时间点 time_point 类型转换为 std::time_t 类型。
static std::time_t to_time_t( const time_point& t ) noexcept;
// 将 std::time_t 类型转换为时间点 time_point 类型。
static std::chrono::system_clock::time_point from_time_t( std::time_t t ) noexcept;
示例:
#define _CRT_SECURE_NO_WARNINGS // localtime()需要这个宏。
#include <iostream>
#include <chrono>
#include <iomanip> // put_time()函数需要包含的头文件。
#include <sstream>
using namespace std;
int main()
{
// 1)静态成员函数 chrono::system_clock::now()用于获取系统时间。(C++时间)
auto now = chrono::system_clock::now();
// 2)静态成员函数 chrono::system_clock::to_time_t()把系统时间转换为 time_t。(UTC 时间)
auto t_now = chrono::system_clock::to_time_t(now);
// t_now = t_now + 24*60*60; // 把当前时间加 1 天。
// t_now = t_now + -1*60*60; // 把当前时间减 1 小时。
// t_now = t_now + 120; // 把当前时间加 120 秒。
// 3)std::localtime()函数把 time_t 转换成本地时间。(北京时)
// localtime()不是线程安全的,VS 用 localtime_s()代替,Linux 用 localtime_r()代替。
auto tm_now = std::localtime(&t_now);
// 4)格式化输出 tm 结构体中的成员。
std::cout << std::put_time(tm_now, "%Y-%m-%d %H:%M:%S") << std::endl;
std::cout << std::put_time(tm_now, "%Y-%m-%d") << std::endl;
std::cout << std::put_time(tm_now, "%H:%M:%S") << std::endl;
std::cout << std::put_time(tm_now, "%Y%m%d%H%M%S") << std::endl;
stringstream ss; // 创建 stringstream 对象 ss,需要包含<sstream>头文件。
ss << std::put_time(tm_now, "%Y-%m-%d %H:%M:%S"); // 把时间输出到对象 ss 中。
string timestr = ss.str(); // 把 ss 转换成 string 的对象。
cout << timestr << endl;
}
三、计时器
steady_clock 类相当于秒表,操作系统只要启动就会进行时间的累加,常用于耗时的统计(精确到
纳秒)。
#include <iostream>
#include <chrono>
using namespace std;
int main()
{
// 静态成员函数 chrono::steady_clock::now()获取开始的时间点。
auto start = chrono::steady_clock::now();
// 执行一些代码,让它消耗一些时间。
cout << "计时开始 ...... \n";
for (int ii = 0; ii < 1000000; ii++) {
// cout << "我是一只傻傻鸟。\n";
}
cout << "计时完成 ...... \n";
// 静态成员函数 chrono::steady_clock::now()获取结束的时间点。
auto end = chrono::steady_clock::now();
// 计算消耗的时间,单位是纳秒。
auto dt = end - start;
cout << "耗时: " << dt.count() << "纳秒("<<(double)dt.count()/(1000*1000*1000)<<" 秒)";
}
240、C++11 线程
在 C++11 之前,C++没有对线程提供语言级别的支持,各种操作系统和编译器实现线程的方法不一
样。
C++11 增加了线程以及线程相关的类,统一编程风格、简单易用、跨平台。 一、创建线程
头文件:#include <thread>
线程类:std::thread
构造函数:
1)thread() noexcept;
默认构造函,构造一个线程对象,不执行任何任务(不会创建/启动子线程)。
2)template< class Function, class... Args >
explicit thread(Function&& fx, Args&&... args );
创建线程对象,在线程中执行任务函数 fx 中的代码,args 是要传递给任务函数 fx 的参数。
任务函数 fx 可以是普通函数、类的非静态成员函数、类的静态成员函数、lambda 函数、仿函数。
3)thread(const thread& ) = delete;
删除拷贝构造函数,不允许线程对象之间的拷贝。
4)thread(thread&& other ) noexcept;
移动构造函数,将线程 other 的资源所有权转移给新创建的线程对象。
赋值函数:
thread& operator= (thread&& other) noexcept;
thread& operator= (const other&) = delete;
线程中的资源不能被复制,如果 other 是右值,会进行资源所有权的转移,如果 other 是左值,禁止
拷贝。
注意:
 先创建的子线程不一定跑得最快(程序运行的速度有很大的偶然性)。
 线程的任务函数返回后,子线程将终止。
 如果主程序(主线程)退出(不论是正常退出还是意外终止),全部的子线程将强行被终止。
示例:
#include <iostream>
#include <thread> // 线程类头文件。
#include <windows.h> // Sleep()函数需要这个头文件。
using namespace std;
// 普通函数。
void func(int bh, const string& str) {
for (int ii = 1; ii <= 10; ii++)
{
cout << "第" << ii << "次表白:亲爱的" << bh << "号," << str << endl;
Sleep(1000); // 休眠 1 秒。
}
}
// 仿函数。
class mythread1
{
public:
void operator()(int bh, const string& str) {
for (int ii = 1; ii <= 10; ii++)
{
cout << "第" << ii << "次表白:亲爱的" << bh << "号," << str << endl;
Sleep(1000); // 休眠 1 秒。
}
}
};
// 类中有静态成员函数。
class mythread2
{
public:
static void func(int bh, const string& str) {
for (int ii = 1; ii <= 10; ii++)
{
cout << "第" << ii << "次表白:亲爱的" << bh << "号," << str << endl;
Sleep(1000); // 休眠 1 秒。
}
}
};
// 类中有普通成员函数。
class mythread3
{
public:
void func(int bh, const string& str) {
for (int ii = 1; ii <= 10; ii++)
{
cout << "第" << ii << "次表白:亲爱的" << bh << "号," << str << endl;
Sleep(1000); // 休眠 1 秒。
}
}
};
int main()
{
// 用普通函数创建线程。
//thread t1(func, 3, "我是一只傻傻鸟。");
//thread t2(func, 8, "我有一只小小鸟。");
// 用 lambda 函数创建线程。
auto f = [](int bh, const string& str) {
for (int ii = 1; ii <= 10; ii++)
{
cout << "第" << ii << "次表白:亲爱的" << bh << "号," << str << endl;
Sleep(1000); // 休眠 1 秒。
}
};
//thread t3(f, 3, "我是一只傻傻鸟。");
// 用仿函数创建线程。
//thread t4(mythread1(), 3, "我是一只傻傻鸟。");
// 用类的静态成员函数创建线程。
//thread t5(mythread2::func, 3, "我是一只傻傻鸟。");
// 用类的普通成员函数创建线程。
mythread3 myth; // 必须先创建类的对象,必须保证对象的生命周期比子线程要长。
thread t6(&mythread3::func, &myth, 3, "我是一只傻傻鸟。"); // 第二个参数必须填对象的
this 指针,否则会拷贝对象。
cout << "任务开始。\n";
for (int ii = 0; ii < 10; ii++) {
cout << "执行任务中......\n";
Sleep(1000); // 假设执行任务需要时间。
}
cout << "任务完成。\n";
//t1.join(); // 回收线程 t1 的资源。
//t2.join(); // 回收线程 t2 的资源。
//t3.join(); // 回收线程 t3 的资源。
//t4.join(); // 回收线程 t4 的资源。
//t5.join(); // 回收线程 t5 的资源。
t6.join(); // 回收线程 t6 的资源。
}
 


网站公告

今日签到

点亮在社区的每一天
去签到