C++ Primer Plus习题及答案-第十八章
习题选自:C++ Primer Plus(第六版)
内容仅供参考,如有错误,欢迎指正 !C++ decltype和返回类型后置
左右值引用和移动语义
C++11 新的类功能
C++11 Lambda表达式
C++11 包装器function
复习题
1. 使用用大括号括起的初始化列表语法重写下述代码。重写后的代码不应使用数组ar:
class Z200
{private:int j;char ch;double z;public:Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv) {}...
};
double x = 8.8;
std::string s = "What a bracing effect!";
int k(99);
Z200 zip(200,'Z',0.675);
std::vector<int> ai(5);
int ar[5] = {3, 9, 4, 7, 1};
for (auto pt = ai.begin(), int i = 0; pt != ai.end(); ++pt, ++i)*pt = ai[i];
重写后代码:
class Z200
{private:int j;char ch;double z;public:Z200(int jv, char chv, zv) : j(jv), ch(chv), z(zv) {}...
};
double x{8.8}; // = {8.8}
std::string s{"What a bracing effect!"};
int k{99};
Z200 zip{200,'Z',0.675};
std::vector<int> ai{3, 9, 4, 7, 1};
2.2. 在下述简短的程序中,哪些函数调用不对?为什么?对于合法的函数调用,指出其引用参数指向的是什么。
#include <iostream>
using namespace std;
double up(double x) { return 2.0* x;}
void r1(const double &rx) {cout << rx << endl;}
void r2(double &rx) {cout << rx << endl;}
void r3(double &&rx) {cout << rx << endl;}
int main()
{double w = 10.0;r1(w);r1(w+1);r1(up(w));r2(w);r2(w+1);r2(up(w));r3(w);r3(w+1);r3(up(w));return 0;
}
-
r1(w);
----合法,形参rx
指向w
。 -
r1(w+1);
----合法,形参rx
指向一个临时变量,这个变量被初始化为w+1
。 -
r1(up(w));
—合法,形参rx
指向一个临时变量,这个变量被初始化为up(w)
的返回值。 -
r2(w);
—合法,形参rx
指向w
。 -
r2(w+1)
; —非法,因为w+1
是一个右值。 -
r2(up(w));
—非法,因为up(w)
的返回值是一个右值。 -
r3(w);
—非法,因为右值引用不能指向左值(如w
)。 -
r3(w+1);
—合法,rx
指向表达式w+1
的临时拷贝。 -
r3(up(w));
—合法,rx
指向up(w)
的临时返回值。
一般而言,将左值传递给const
左值引用参数的时候,参数将被初始化为左值。将右值传递给函数时,const
左值引用参数将指向右值的临时拷贝。将左值传递给非const
左值引用参数时,参数将被初始化为左值;但非const
左值形参不能接受右值实参。
3. a. 下述简短的程序显示什么?为什么?
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << "const double & rx\n"; }
void r1(double &rx) { cout << "double & rx\n"; }
int main() {double w = 10.0;r1(w);r1(w + 1);r1(up(w));return 0;
}
b. 下述简短的程序显示什么?为什么?
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(double &rx) { cout << "double & rx\n"; }
void r1(double &&rx) { cout << "double && rx\n"; }
int main() {double w = 10.0;r1(w);r1(w + 1);r1(up(w));return 0;
}
c. 下述简短的程序显示什么?为什么?
#include <iostream>
using namespace std;
double up(double x) { return 2.0 * x; }
void r1(const double &rx) { cout << "const double & rx\n"; }
void r1(double &&rx) { cout << "double && rx\n"; }
int main() {double w = 10.0;r1(w);r1(w + 1);r1(up(w));return 0;
}
a.
double & rx
const double & rx
const double & rx
非const
左值引用与左值实参匹配,因此 r1(w);
调用void r1(double &rx)
。另外两个实参均为右值,const左值引用可以指向他们的拷贝。【将右值传递给函数时,const
左值引用参数将指向右值的临时拷贝。】。
b.
double & rx
double && rx
double && rx
左值引用与左值实参w
匹配,而右值引用与两个右值实参匹配。
c.
const double & rx
double && rx
double && rx
const
左值引用与左值实参w
匹配,而右值引用与两个右值实参匹配。
总之,非const
左值形参与左值实参匹配,非cosnt
右值形参与右值实参匹配;const
左值形参可以与左值或右值实参匹配。如果可供选择的话,编译器优先选择前两种方式。
4. 哪些成员函数是特殊的成员函数?它们特殊的原因是什么?
特殊成员函数:默认构造函数、复制构造函数、移动构造函数、析构函数、复制赋值运算符和移动赋值运算符。这些函数之所以特殊,是因为编译器将根据情况自动提供它们的默认版本。
5. 假设Fizzle类只有如下所示的数据成员:
class Fizzle
{private:double bubbles[4000];...
};
为什么不适合给这个类定义移动构造函数?要让这个类适合定义移动构造函数,应如何修改存储4000个double值的方式?
移动构造函数是在转让数据所有权可行的时候是合适的。但对于标准数组没有转让所有权的机制,因此不适合给该类定义移动构造函数。如果Fizzle
使用指针和动态内存分配来存储这4000个double
值,即可以将数据的地址赋给新指针,以转让其所有权,则适合给Fizzle
定义移动构造函数。
6. 修改下述简短的程序,使其使用lambda表达式而不是f1( )。请不要修改show2( )。
#include <iostream>
template<typename T>
void show2(double x, T& fp) {std::cout << x << " -> " << fp(x) << '\n';}
double f1(double x) { return 1.8*x + 32;}
int main()
{show2(18.0, f1);return 0;
}
修改后:
#include <iostream>
template <typename T>
void show2(double x, T& fp) { std::cout << x << " -> " << fp(x) << '\n';}
//void show2(double x, T fp) {std::cout << x << " -> " << fp(x) << '\n';}
int main() {auto f2 = [](double x) { return 1.8 * x + 32; };show2(18.0, f2);//show2(18.0, [](double x){return 1.8*x + 32;});return 0;
}
7. 修改下述简短而丑陋的程序,使其使用lambda表达式而不是函数符Adder。请不要修改sum( )。
#include <iostream>
#include <array>
const int Size = 5;
template<typename T>
void sum(std::array<double,Size> a, T& fp);
class Adder
{double tot;public:Adder(double q = 0) : tot(q) {}void operator()(double w) { tot +=w;}double tot_v () const {return tot;};
};
int main()
{double total = 0.0;Adder ad(total);std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};sum(temp_c,ad);total = ad.tot_v();std::cout << "total: " << ad.tot_v() << '\n';return 0;
}
template<typename T>
void sum(std::array<double,Size> a, T& fp)
{for(auto pt = a.begin(); pt != a.end(); ++pt){fp(*pt);}
}
修改后:
#include <array>
#include <iostream>
const int Size = 5;
template <typename T>
void sum(std::array<double, Size> a, T& fp);int main() {double total = 0.0;std::array<double, Size> temp_c = {32.1, 34.3, 37.8, 35.2, 34.7};auto f = [&total](double x) { total += x; };sum(temp_c, f);std::cout << "total: " << total << '\n';return 0;
}
template <typename T>
void sum(std::array<double, Size> a, T& fp) {for (auto pt = a.begin(); pt != a.end(); ++pt) {fp(*pt);}
}
编程练习
1. 下面是一个简短程序的一部分:
int main()
{using namespace std;// list of double deduced from list contentsauto q = average_list({15.4, 10.7, 9.0});cout << q << endl;// list of int deduced from list contentscout << average_list({20, 30, 19, 17, 45, 38} ) << endl;// forced list of doubleauto ad = average_list<double>({'A', 70, 65.33});cout << ad << endl;return 0;
}
请提供函数average_list( ),让该程序变得完整。它应该是一个模板函数,其中的类型参数指定了用作函数参数的initilize_list模板的类型以及函数的返回类型。
修改后:
#include <algorithm>
#include <initializer_list>
#include <iostream>
using namespace std;template <typename T>
T average_list(initializer_list<T> l) {T sum = 0;if (l.size() == 0) return 0;for_each(l.begin(), l.end(), [&sum](T t) { sum += t; });return sum / l.size();
}int main() {using namespace std;// list of double deduced from list contentsauto q = average_list({15.4, 10.7, 9.0});cout << q << endl;// list of int deduced from list contentscout << average_list({20, 30, 19, 17, 45, 38}) << endl;// forced list of doubleauto ad = average_list<double>({'A', 70, 65.33});cout << ad << endl;return 0;
}
2. 下面是类Cpmv的声明:
class Cpmv
{public:struct Info{std::string qcode;std::string zcode;};private:Info *pi;public:Cpmv();Cpmv(std::string q, std::string z);Cpmv(const Cpmv & cp);Cpmv(Cpmv && mv);~Cpmv();Cpmv & operator=(const Cpmv & cp);Cpmv & operator=(Cpmv && mv);Cpmv operator+(const Cpmv & obj) const;void Display() const;
};
函数operator+ ( )应创建一个对象,其成员qcode和zcode有操作数的相应成员拼接而成。请提供为移动构造函数和移动赋值运算符实现移动语义的代码。编写一个使用所有这些方法的程序。为方便测试,让各个方法都显示特定的内容,以便知道它们被调用。
代码如下:
#include <iostream>using namespace std;class Cpmv {public:struct Info {std::string qcode;std::string zcode;};private:Info *pi;public:Cpmv();Cpmv(std::string q, std::string z);Cpmv(const Cpmv &cp);Cpmv(Cpmv &&mv);~Cpmv();Cpmv &operator=(const Cpmv &cp);Cpmv &operator=(Cpmv &&mv);Cpmv operator+(const Cpmv &obj) const;void Display() const;
};int main() {Cpmv c1;Cpmv c2("abc", "123");Cpmv c3(c2);c1 = c2;c1.Display();Cpmv c4(move(c1));c4.Display();Cpmv c5;c5 = move(c2);c5.Display();return 0;
}Cpmv::Cpmv() {pi = new Info;pi->qcode = "";pi->zcode = "";cout << "Cpmv() called.\n";
}Cpmv::Cpmv(std::string q, std::string z) {pi = new Info;pi->qcode = q;pi->zcode = z;cout << "Cpmv(std::string q, std::string z) called.\n";
}Cpmv::Cpmv(const Cpmv &cp) {pi = new Info;pi->qcode = cp.pi->qcode;pi->zcode = cp.pi->zcode;cout << "Cpmv(const Cpmv &cp) called.\n";
}Cpmv::Cpmv(Cpmv &&mv) {pi = mv.pi;mv.pi = nullptr;cout << "Cpmv(Cpmv &&mv) called.\n";
}Cpmv::~Cpmv() {delete pi;cout << "~Cpmv() called.\n";
}Cpmv &Cpmv::operator=(const Cpmv &cp) {cout << "Cpmv &operator=(const Cpmv &cp) called.\n";if (this == &cp) {return *this;}delete pi;pi = new Info;pi->qcode = cp.pi->qcode;pi->zcode = cp.pi->zcode;return *this;
}Cpmv &Cpmv::operator=(Cpmv &&mv) {cout << "Cpmv &operator=(Cpmv &&mv) called.\n";if (this == &mv) {return *this;}delete pi;pi = mv.pi;mv.pi = nullptr;return *this;
}Cpmv Cpmv::operator+(const Cpmv &obj) const {cout << "Cpmv operator+(const Cpmv &obj) called.\n";Cpmv cv;cv.pi->qcode = this->pi->qcode + obj.pi->qcode;cv.pi->zcode = this->pi->zcode + obj.pi->zcode;return cv;
}void Cpmv::Display() const {cout << "The qcode is " << this->pi->qcode << endl;cout << "The zcode is " << this->pi->zcode << endl;
}
3. 编写并测试可变参数模板函数sum_value( ),它接受任意长度的参数列表(其中包含数值,但可以是任何类型),并以long double的方式返回这些数值的和。
main.cpp:
#include <iostream>
#include <string>// definition for 1 parameter
template <typename T>
long double sum_value(const T& value) {return value;
}// definition for 2 or more parameters
template <typename T, typename... Args>
long double sum_value(const T& value, const Args&... args) {return value + sum_value(args...);
}int main() {int n = 14;double x = 2.71828;std::cout << sum_value(n, x, 'a') << std::endl;return 0;
}
4. 使用lambda重新编写程序清单16.15。具体地说,使用一个有名称的lambda替换函数outint( ),并将函数符替换为两个匿名lambda表达式。
main.cpp:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <list>auto outint_l = [](int n) { std::cout << n << " "; };int main() {using std::cout;using std::endl;using std::list;int vals[10] = {50, 100, 90, 180, 60, 210, 415, 88, 188, 201};list<int> yadayada(vals, vals + 10); // range constructorlist<int> etcetera(vals, vals + 10);// C++11 can use the following instead// list<int> yadayada = {50, 100, 90, 180, 60, 210, 415, 88, 188, 201};// list<int> etcetera {50, 100, 90, 180, 60, 210, 415, 88, 188, 201};cout << "Original lists:\n";for_each(yadayada.begin(), yadayada.end(), outint_l);cout << endl;for_each(etcetera.begin(), etcetera.end(), outint_l);cout << endl;yadayada.remove_if([](int n) { return n > 100; }); // use a named function objectetcetera.remove_if([](int n) { return n > 200; }); // construct a function objectcout << "Trimmed lists:\n";for_each(yadayada.begin(), yadayada.end(), outint_l);cout << endl;for_each(etcetera.begin(), etcetera.end(), outint_l);cout << endl;return 0;
}
相关文章:
C++ Primer Plus习题及答案-第十八章
习题选自:C Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! C decltype和返回类型后置 左右值引用和移动语义 C11 新的类功能 C11 Lambda表达式 C11 包装器function 复习题 1. 使用用大括号括起的初始化列表语法重写下述代码。重写后…...
Redis事务控制
1.Redis事务控制的相关命令 命令名作用MULTI表示开始收集命令,后面所有命令都不是马上执行,而是加入到一个队列中。EXEC执行MULTI后面命令队列中的所有命令。DISCARD放弃执行队列中的命令。WATCH“观察“、”监控“一个KEY,在当前队列外的其…...
Springcloud OpenFeign 详解
一、概述OpenFeign是springcloud在Feign的基础上支持了SpringMVC的注解,整合了hystrix,同时,可以和Eureka和ribbon配合使用,如RequestMapping等等。OpenFeign的FeignClient可以解析SpringMVC的RequestMapping注解下的接口…...

软件测试期末
考原题就是爽 软件测试技术 知识点整理 https://wenku.baidu.com/view/524c900f4b2fb4daa58da0116c175f0e7cd11913.html 关键知识点 https://www.cnblogs.com/whylaughing/category/813559.html?page1 边界值法不选择无效数据 边界值分析法的基本思想 选取正好等于&am…...

关于Java的深拷贝和浅拷贝
文章目录1.拷贝的引入1.1引用拷贝1.2对象拷贝2.深拷贝与浅拷贝2.1浅拷贝2.2深拷贝1.拷贝的引入 1.1引用拷贝 创建一个指向对象的引用变量的拷贝 Teacher teacher new Teacher("Taylor",26); Teacher otherteacher teacher; System.out.println(teacher); System…...

固定值电阻的检测方法总结
🏡《总目录》 目录 1,概述2,测量方法3,检测方法3.1,读值3.2,测量3.3,排故4,总结1,概述 本文简单总结固定值电阻的测量与检查方法要点和注意事项。 2,测量方法 对于固定值电阻的测量来讲,直接将万用表红黑表笔分别插入到如下图所示的红色和黑色接线端。然后将万用表…...
打印机相关
打印机相关 打印机协议 ipp,printer-job-language,lpd协议。他们的默认端口分别是631,9100和515. printer-job-language(RAW协议) 9100端口的printer-job-language,又称为RAW协议。目前遇到的问题是,此端口发送数据,打印机直接打印,除非发送正确的printer-job-lan…...
入门力扣自学笔记235 C++ (题目编号:2347)
2347. 最好的扑克手牌 题目: 给你一个整数数组 ranks 和一个字符数组 suit 。你有 5 张扑克牌,第 i 张牌大小为 ranks[i] ,花色为 suits[i] 。 下述是从好到坏你可能持有的 手牌类型 : "Flush":同花&…...

k8s-二进制部署
文章目录一、环境二、步骤1、安装cfssl工具2、部署etcd集群3、在node节点安装docker组件4、安装flannel组件部署master节点组件部署node节点部署kube-proxy组件三、测试一、环境 角色服务器地址组件master192.168.174.140kube-apiserver,kube-controller-manager&a…...

前缀和差分(C/C++)
目录 1. 前缀和的定义 2. 一维前缀和 2.1 计算公式 2.2 用途 2.3 小试牛刀 3. 二维前缀和 3.1 用途 1. 前缀和的定义 对于一个给定的数列A,他的前缀和数中 S 中 S[ i ] 表示从第一个元素到第 i 个元素的总和。 如下图:绿色区域的和就是前缀和数组…...

回文子串的数量[寻找回文子串的完整思路过程]
寻找回文子串的完整思路过程前言一、回文串的数量二、动态规划1、完整思考过程2、go总结参考文献前言 回文字符串,就是从左遍历和从右遍历的字符是相同顺序的,转换一下,就是该字符串是对称的。寻找回文子串面临两个直接的问题,1-…...

CCNP350-401学习笔记(301-350题)
301、Drag and drop the virtual component from the left onto their descriptions on the right. 302、Which two actions, when applied in the LAN network segment, will facilitate Layer 3 CAPWAP discovery for lightweight AP? (Choose two.)A. Utilize DHCP option …...

【LeetCode】No.225. 用队列实现栈 -- Java Version
题目链接:https://leetcode.cn/problems/implement-stack-using-queues/ 1. 题目介绍(225. 用队列实现栈) 请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通栈的全部四种操作(push、t…...

45个写规范代码的小技巧
目录 1、规范命名 2、规范代码格式 3、写好代码注释 4、try catch 内部代码抽成一个方法 5、方法别太长 6、抽取重复代码 7、多用return 8、if条件表达式不要太复杂 9、优雅地参数校验 10、统一返回值 11、统一异常处理 12、尽量不传递null值 13、尽量不返回null值…...

MindFusion Diagramming for Java, 最新版 Crack
Diagramming for Java, V4.6.1 A unique Java Swing library for any type of flowchart.您需要的每一个图表功能 图表、方案、图形、网络、算法、树、图表 - 所有这些都是使用 MindFusion Diagramming for Java 工具快速轻松地构建的。结果令人着迷。 Java Dagram 库ÿ…...

中间件安全—Apache常见漏洞
中间件安全—Apache常见漏洞1.Apache常见漏洞1.1.Apache介绍1.2.Apache HTTPD 换行解析漏洞(CVE-2017-15715)1.2.1.漏洞介绍1.2.2.漏洞环境1.2.2.1.运行漏洞环境1.2.2.2.访问漏洞环境1.2.3.漏洞复现1.2.3.1.拦截1.2.3.2.添加换行1.2.3.3.访问文件1.3.Apa…...

Spring IOC 容器 Bean 加载过程
Spring IOC 容器 Bean 加载过程 Spring 对于我们所有的类对象进行了统一抽象,抽象为 BeanDefinition ,即 Bean 的定义,其中定义了类的全限定类名、加载机制、初始化方式、作用域等信息,用于对我们要自动装配的类进行生成。 Sprin…...
【DRF】Django Rest Framework(5.DRF中的通用视图类-GenericAPIView方法说明与使用说明)
1. GenericAPIView [通用视图类],概述 继承自 APIView增加了操作序列化器和数据库查询的方法,作用是为下面Mixin扩展类的执行提供方法支持。通常在使用时,可搭配一个或者多个Mixin扩展类源码 当我们查看 GenericAPIView 的源码时,…...

STM32 OTA应用开发——自制BootLoader
STM32 OTA应用开发——自制BootLoader 目录STM32 OTA应用开发——自制BootLoader前言1 环境搭建2 BootLoader工作原理以及常见分区介绍3 BootLoader的制作4 烧录下载配置5 运行测试结束语前言 什么是OTA? 百度百科:空中下载技术(Over-the-Ai…...
时域和频域的简单理解
目录文章背景结论举例说明说回频域连续或离散总结文章背景 时域和频域在傅里叶变换和拉普拉斯变换,z变换中经常提到的高频词。本文的重点就是想说明怎么理解 “频域” 这个名词。 结论 频域就是一个信号 所有组成频率的取值范围的集合 举例说明 以大家从中小学开…...
挑战杯推荐项目
“人工智能”创意赛 - 智能艺术创作助手:借助大模型技术,开发能根据用户输入的主题、风格等要求,生成绘画、音乐、文学作品等多种形式艺术创作灵感或初稿的应用,帮助艺术家和创意爱好者激发创意、提高创作效率。 - 个性化梦境…...
rknn优化教程(二)
文章目录 1. 前述2. 三方库的封装2.1 xrepo中的库2.2 xrepo之外的库2.2.1 opencv2.2.2 rknnrt2.2.3 spdlog 3. rknn_engine库 1. 前述 OK,开始写第二篇的内容了。这篇博客主要能写一下: 如何给一些三方库按照xmake方式进行封装,供调用如何按…...
在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:
在 HarmonyOS 应用开发中,手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力,既支持点击、长按、拖拽等基础单一手势的精细控制,也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档,…...
python爬虫:Newspaper3k 的详细使用(好用的新闻网站文章抓取和解析的Python库)
更多内容请见: 爬虫和逆向教程-专栏介绍和目录 文章目录 一、Newspaper3k 概述1.1 Newspaper3k 介绍1.2 主要功能1.3 典型应用场景1.4 安装二、基本用法2.2 提取单篇文章的内容2.2 处理多篇文档三、高级选项3.1 自定义配置3.2 分析文章情感四、实战案例4.1 构建新闻摘要聚合器…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...

Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

以光量子为例,详解量子获取方式
光量子技术获取量子比特可在室温下进行。该方式有望通过与名为硅光子学(silicon photonics)的光波导(optical waveguide)芯片制造技术和光纤等光通信技术相结合来实现量子计算机。量子力学中,光既是波又是粒子。光子本…...

JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...