码迷,mamicode.com
首页 > 编程语言 > 详细

C++Primer 5th 练习 12.19

时间:2016-12-31 21:40:43      阅读:333      评论:0      收藏:0      [点我收藏+]

标签:ack   代码   练习题   运行结果截图   保存   位置   容器   prim   log   

 

  这阵子真是太忙了, 连续做了四个课设。 当然这并不能作为好久没写博客的借口, 没写博客的主要原因只有一个: 。 最近又开始回顾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. 需要用到友元类中的具体成员时,必须保证友元类已经定义。

列表初始化

头文件定义规范

 

C++Primer 5th 练习 12.19

标签:ack   代码   练习题   运行结果截图   保存   位置   容器   prim   log   

原文地址:http://www.cnblogs.com/acm1314/p/6240195.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!