C++Primer 5th 练习 12.19

  这阵子真是太忙了, 连续做了四个课设。 当然这并不能作为好久没写博客的借口, 没写博客的主要原因只有一个: 。 最近又开始回顾C++的语法与特性(据说C++就是一门需要反复回顾的语言),以及学习C++的编程规范。 敲了C++Primer 5th 上的一道典型的练习题,纪念一下这即将过去的2016.

  题目描述: 定义你自己版本的 StrBlobPtr, 更新 StrBlob类, 加入恰当的 friend 声明及begin 和 end 成员。

  这道题目主要是练习 智能指针 share_ptrweak_ptr

  我的环境: Win10 + VS2015

  声明 StrBlob 类和 类StrBlobPtr的文件: StrBlob.h  

 1 #pragma once
 2 #ifndef PRACTICE_STRBLOB_H_
 3 #define PRACTICE_STRBLOB_H_
 4 #include <memory>
 5 #include <vector>
 6 #include <string>
 7 #endif  PRACTICE_STRBLOB_H_
 8
 9 // 对于 StrBlob 中的友元声明来说,这个前置声明是必要的
10 class StrBlobPtr;
11 class StrBlob {
12     friend class StrBlobPtr;
13 public:
14     typedef std::vector<std::string>::size_type size_type;
15     StrBlob():data(std::make_shared<std::vector<std::string>>()) { }
16     StrBlob(std::initializer_list<std::string>il):data(std::make_shared<std::vector<std::string>>(il)){ }
17     size_type size() const { return data->size();  }
18     bool empty() const { return data->empty();  }
19     // 添加和删除元素
20     void push_back(const std::string &t) { data->push_back(t);  }
21     void pop_back();
22     // 元素访问
23     std::string& front();
24     std::string& back();
25     const std::string& front() const;
26     const std::string& back() const;
27
28     // 返回指向首元素和尾元素的 StrBlobPtr
29     StrBlobPtr begin();
30     StrBlobPtr end();
31 private:
32     std::shared_ptr<std::vector<std::string>> data;
33     void check(size_type i, const std::string &msg) const;
34 };
35
36
37 // 对于访问一个不存在元素的尝试, StrBlobPtr抛出一个异常
38 class StrBlobPtr {
39 public:
40     StrBlobPtr(): curr(0) { }
41     StrBlobPtr(StrBlob &a, size_t sz = 0):
42         wptr(a.data), curr(sz) { }
43     std::string& deref() const;
44     StrBlobPtr& incr();        // 前缀递增
45 private:
46     // 若检查成功, check返回一个指向 vector 的 shared_ptr
47     std::shared_ptr<std::vector<std::string>>
48         check(std::size_t i, const std::string& msg) const;
49     // 保存一个 weak_ptr, 意味着底层 vector 可能会被销毁
50     std::weak_ptr<std::vector<std::string>> wptr;
51     std::size_t curr;        // 在数组中的当前位置
52 };
53
54
55
56  

  实现 StrBlob 类和 类StrBlobPtr的文件: StrBlob.cpp

 1 #include "stdafx.h"
 2 #include "StrBlob.h"
 3
 4 //-----------------------------------
 5 //        类 StrBlob 的实现
 6 //-----------------------------------
 7 void StrBlob::pop_back()
 8 {
 9     check(0, "pop_back on empty StrBlob");
10     data->pop_back();
11 }
12
13 std::string& StrBlob::front()
14 {
15     // 如果 vector 为空, check 会抛出一个异常
16     check(0, "front on empty StrBlob");
17     return data->front();
18 }
19
20 std::string& StrBlob::back()
21 {
22     // 如果 vector 为空, check 会抛出一个异常
23     check(0, "back on empty StrBlob");
24     return data->back();
25 }
26
27 const std::string& StrBlob::front() const
28 {
29     check(0, "front on empty StrBlob");
30     return data->front();
31 }
32
33 const std::string& StrBlob::back() const
34 {
35     check(0, "back on empty StrBlob");
36     return data->back();
37 }
38
39 void StrBlob::check(size_type i, const std::string& msg) const
40 {
41     if (i >= data->size())
42         throw std::out_of_range(msg);
43 }
44
45 std::string & StrBlobPtr::deref() const
46 {
47     auto p = check(curr, "dereferemce past end");
48     return (*p)[curr];    // (*p) 是对象所指向的 vector
49 }
50
51
52 //    必须在 StrBlobPtr 定义之后进行定义
53 StrBlobPtr StrBlob::begin()
54 {
55     return StrBlobPtr(*this);
56 }
57
58 // 必须在 StrBlobPtr 定义之后进行定义
59 StrBlobPtr StrBlob::end()
60 {
61     auto ret = StrBlobPtr(*this, data->size());
62     return ret;
63 }
64
65
66 //----------------------------------------
67 //         类 StrBlobPtr 的实现
68 //----------------------------------------
69 StrBlobPtr & StrBlobPtr::incr()
70 {
71     // 如果 curr 已经指向容器的尾后位置, 就不能递增它
72     check(curr, "increment past end of StrBlobPtr");
73     ++curr;        // 推进当前位置
74     return *this;
75 }
76
77 std::shared_ptr<std::vector<std::string>> StrBlobPtr::check(std::size_t i, const std::string & msg) const
78 {
79     auto ret = wptr.lock();            // 检查 vector 是否还存在
80     if (!ret)
81         throw std::runtime_error("unbound StrBlobPtr");
82     if (i >= ret->size())
83         throw std::out_of_range(msg);
84
85     return ret;        // 否则, 返回指向 vector 的 shared_ptr
86 }

  用于测试的文件: practice_12.19.cpp

 1 // practice_12.19.cpp : 定义控制台应用程序的入口点。
 2 //
 3
 4 #include "stdafx.h"
 5 #include "StrBlob.h"
 6 #include <iostream>
 7 using namespace std;
 8
 9 int main()
10 {
11     StrBlob blob{ "So", "Fun", "So", "Good" };
12     StrBlobPtr blobPtr(blob);
13     cout << blob.front() << endl;
14     blobPtr.incr();
15     cout << blobPtr.deref() << endl;
16     blobPtr = blob.begin();
17     cout << blobPtr.deref() << endl;
18     cout << blob.back() << endl;
19     return 0;
20 }

运行结果截图:

  这道题目是很经典的,但是很不幸, C++Primer 5th (中文版)上,却把这道题目的代码写错了一丢丢。

回顾一下这道题涉及的主要姿势:

一般程序使用动态内容的原因

  1. 程序不知道自己需要使用多少对象
  2. 程序不知道所需对象的准确类型
  3. 程序需要在多个对象间共享数据(这个例子就是共享数据的问题)

友元的相关知识

  1. 友元类一定要事先声明(或定义)
  2. 需要用到友元类中的具体成员时,必须保证友元类已经定义。

列表初始化

头文件定义规范

时间: 2024-10-30 09:18:48

C++Primer 5th 练习 12.19的相关文章

12.17 Nginx负载均衡;12.18 ssl原理;12.19 生产ssl密钥对;12.20 Nginx配置ssl

扩展: 针对请求的uri来代理 http://ask.apelearn.com/question/1049 根据访问的目录来区分后端web http://ask.apelearn.com/question/920 12.17 Nginx负载均衡 1. 安装dig命令: [[email protected] ~]# yum install -y bind-utils 2. 用dig获取qq.com的ip地址: [[email protected] ~]# dig qq.com 3. 创建ld.co

读书笔记:C++ Primer系列(12)—— 类型转换

题记:类型转换就是将给定类型的表达式转换为另一种类型.C++中的转型可分为两种:隐式类型转换和显式类型转换. 隐式转换 隐式转换不需要任何转换运算符,编译器会自动根据类型兼容性进行不同类型之间的转换.一般情况下,在C/C++中这种转换多出现在基本数值类型上,其基本原则就是所需内存小的类型可以直接转换成内存大相同的或者. 例如: int a=0; a=3.1415+3; 运行结果为:6 解释: 上述加法操作中,其操作数是两个不同类型的值:3.1415是double类型的字面值常量,3是int类型的

TCL 中upvar 用法 (摘自http://www.cnblogs.com/kane1990/archive/2011/12/19/2293981.html)

可以用 upvar 命令模拟传引用调用的行为,这对数组特别有用.如果a是一个数组,就不能像myproc $a这样把它传给过程myproc,因为并没有 对应整个数组的值:只有对应各个数组元素的值. 但是可以把数组名传给过程,myproc a,然后使用upvar命令在过程中访问数组的元素. 下面是在过程中使用upvar的简单示例,输出一个数组的内容: proc printArray {name} { upvar $name a foreach el [ lsort [ array names a]]

2017.12.19 2周2次课

2017.12.19二周第二次课 2.10 环境变量PATH echo用来输出PATH的值.PATH前面的$是变量的前缀符号 1.你的命令在上述几个目录里面,在输入命令时就不用输入绝对路径,直接使用.因为在输入命令时,系统会在上述的几个目录里去寻找这个命令.当然也可以输入绝对路径 Copy命令[ls]到目录tmp下,并改名[ls2],二者实现的功能一样 直接输入命令[ls2],确不行.因为命令[ls2]不在"/usr/local/sbin:/usr/local/bin:/usr/sbin:/us

12.19&amp;12.20 -基础命令练习二

12.19&12.20 基础命令练习二 第1章 Linux开机启动过程 linux启动过程 1.开启开关 2.bios开机自检 3.mbr引导 4.grub菜单 选择内核 5.加载内核 6.启动init进程  init进程是linux启动的时候运行的第一个进程 7.从/etc/inittab读取运行级别 8.根据/etc/rc.d/rc.sysinit 初始化系统 (设置主机名 ip地址) 9.根据运行级别启动对应的软件(开机自启动软件) 10.运行mingetty 显示登录界面 第2章 PAT

12.17 Nginx负载均衡;12.18 ssl原理;12.19 生产ssl密钥对;12.20 N

12.17 Nginx负载均衡:12.18 ssl原理:12.19 生产ssl密钥对:12.20 Nginx配置ssl 扩展: 针对请求的uri来代理 : http://ask.apelearn.com/question/1049 根据访问的目录来区分后端的web : http://ask.apelearn.com/question/920 nginx长连接 : http://www.apelearn.com/bbs/thread-6545-1-1.html nginx算法分析 : http:/

12.17Nginx负载均衡12.18ssl原理12.19生成ssl密钥对 20Nginx配置ssl

12.17Nginx负载均衡查看域名的IP,用dig命令首先安装 一下dig命令yum install -y bind-utils这时候就可以查看到qq.com的ipb 没有更改配置文件前只能访问默认页,更改配置文件之后,加载配置文件再访问curl x127.0.0.1:80 www.qq.com 就不一样了,进入主页了.只不过反馈回来的是网页的原码nginx不支持代理https,新版本 的也只支持http tcp12.18 ssl原理12.19 生成ssl密钥对需要安装 一个包,查看一个命令需

12.17 Nginx负载均衡 12.18 ssl原理 12.19 生成ssl密钥对 12.20 N

12.17 Nginx负载均衡 [[email protected] ~]# yum install -y bind-utils[[email protected] ~]# dig www.qq.comANSWER SECTION:www.qq.com. 73 IN A 59.37.96.63www.qq.com. 73 IN A 14.17.42.40www.qq.com. 73 IN A 14.17.32.211[[email protected] ~]# curl -x127.0.0.1:

1.命名规范很重要——开局要好,(C++ primer 5th,命名规范下有一句话:若能坚持,必将有效)

1.1.标识符要能体现实际含义 少用缩写 int price_count_reader; // 无缩写 int num_errors; // “num” 本来就很常见 int num_dns_connections; // 人人都知道 “DNS” 是啥 Warning int n; // 莫名其妙. int nerr; // 怪缩写. int n_comp_conns; // 怪缩写. int wgc_connections; // 只有贵团队知道是啥意思. int pc_reader; //