IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> 《C++ Primer》第13章 13.5节习题答案 -> 正文阅读

[C++知识库]《C++ Primer》第13章 13.5节习题答案

《C++ Primer》第13章 拷贝控制

13.5节 动态内存管理类 习题答案

练习13.39:编写你自己版本的StrVec,包括自己版本的reserve、capacity(参见9.4节,第318页)和resize(参见9.3.5节,第314页)。

【出题思路】

本题练习设计自己管理内存的类。

【解答】

#ifndef STRVEC13_39_H
#define STRVEC13_39_H


#include <string>
#include <memory>
#include <utility>

class StrVec
{
public:
    StrVec(): elements(nullptr), first_free(nullptr), cap(nullptr)
    {

    }
    StrVec(const StrVec&);
    StrVec& operator=(const StrVec&);
    ~StrVec();

    void push_back(const std::string &);
    size_t size() const
    {
        return first_free - elements;
    }
    size_t capacity() const
    {
        return cap - elements;
    }
    std::string *begin() const
    {
        return elements;
    }
    std::string *end() const
    {
        return first_free;
    }
    void reserve(size_t count);//重分配容量
    void resize(size_t);//重置元素个数

private:
    std::allocator<std::string> alloc;//分配元素
    void chk_n_alloc()
    {
        if(size() == capacity())
            reallocate();
    }
    std::pair<std::string *, std::string *> alloc_n_copy(const std::string *, const std::string *);
    void free();
    void reallocate();
    std::string *elements;      //分配的内存中的首元素
    std::string *first_free;    //最后一个实际元素之后的位置
    std::string *cap;           //分配的内存末尾之后的位置
};

#endif // STRVEC13_39_H
#include "StrVec13_39.h"
#include <iostream>
#include <vector>
#include <utility>

void StrVec::push_back(const std::string &s)
{
    chk_n_alloc();
    alloc.construct(first_free++, s);
}

std::pair<std::string *, std::string *> StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
    auto data = alloc.allocate(e - b);
    return {data, uninitialized_copy(b, e, data)};
}

void StrVec::free()
{
    if(elements)
    {
        for(auto p = first_free; p != elements;)
            alloc.destroy(--p);
        alloc.deallocate(elements, cap - elements);
    }
}

StrVec::StrVec(const StrVec &s)
{
    auto newdata = alloc_n_copy(s.begin(), s.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

StrVec::~StrVec()
{
    free();
}

StrVec &StrVec::operator=(const StrVec &rhs)
{
    auto data = alloc_n_copy(rhs.begin(), rhs.end());
    free();
    elements = data.first;
    first_free = cap = data.second;
    return *this;
}

void StrVec::reallocate()
{
    auto newcapacity = size() ? 2 * size() : 1;
    auto newdata = alloc.allocate(newcapacity);
    auto dest = newdata;
    auto elem = elements;
    for(size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++));
    free();
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}

void StrVec::reserve(size_t count)
{
    if(size() < count)
    {
        auto newdata = alloc.allocate(count);
        auto dest = newdata;
        auto elem = elements;
        for(size_t i = 0; i != size(); ++i)
            alloc.construct(dest++, std::move(*elem++));
        free();
        elements = newdata;
        first_free = dest;
        cap = elements + count;
    }
}

void StrVec::resize(size_t count)
{
    if(count < size())
    {
        for(auto iter = elements + count; iter != first_free; ++iter)
            alloc.destroy(iter);
        first_free = elements + count;
    }

    if(count > size())
    {
        for(size_t i = 0; i != count - size(); ++i)
            alloc.construct(first_free++, std::string());
    }
}

int main()
{
    StrVec vec;
    vec.push_back("scott");
    vec.push_back("camle");
    vec.push_back("星期六");
    vec.push_back("十月");
    vec.push_back("李河");
    vec.push_back("何乐而不为呢");
    std::cout << "strVec=====================size==" << vec.size() << std::endl;
    return 0;
}

运行结果:? strVec=====================size==6

练习13.40:为你的StrVec类添加一个构造函数,它接受一个initializer_list<string>参数。

【出题思路】

本题练习设计列表初始化。

【解答】

通过begin和end获得列表的整个范围,利用辅助函数alloc_n_copy分配足够多的空间,并将范围中的元素拷贝过去即可:

StrVec::StrVec(std::initializer_list<std::string> il)
{
    //调用alloc_n_copy分配与列表il中元素数目一样多的空间
    auto newdata = alloc_n_copy(il.begin(), il.end());
    elements = newdata.first;
    first_free = cap = newdata.second;
}

练习13.41:在push_back中,我们为什么在construct调用中使用后置递增运算?如果使用前置递增运算的话,会发生什么?

【出题思路】

理解几个指针的含义。

【解答】

因为first_free指向第一个空闲位置,也就是最后一个string的尾后位置。当添加新string时,应该保存在first_free指向的位置,然后将first_free推进一个位置,因此后置递增运算恰好符合要求。

如果使用前置递增运算,则是先将first_free推进一个位置,然后将新string保存在新位置上。显然,这种方法意味着first_free指向最后一个string,而非尾后位置,与first_free的设定不吻合。

练习13.42:在你的TextQuery和QueryResult类(参见12.3节,第431页)中用你的StrVec类代替vector<string>,以此来测试你的StrVec类。

【出题思路】

练习StrVec的使用。

【解答】

对TextQuery.h、QueryResult.h和TextQuery.cpp做如下修改:

1. TextQuery.h中file成员的定义改为:
??? std::shared_ptr<StrVec> file; //输入字体
2. QueryResult.h中file成员的定义改为:
??? std::shared_ptr<StrVec> file;
构造函数的第三个参数改为:std::shared_ptr<StrVec> get_file() {return file;}
3.TextQuery.cpp中构造函数初始化file成员的操作改为:
??? TextQuery::TextQuery(ifstream &is):file(new StrVec)

与第12章的练习类似,由于类的封装特性,主程序不用进行任何修改。

练习13.43:重写free成员,用for_each和lambda(参见10.3.2节,第346页)来代替for循环destroy元素。你更倾向于哪种实现,为什么?

【出题思路】

复习lambda的定义和使用。

【解答】

将for循环改成如下形式即可。注意,elements和first_free是string*类型,因此它们指出的范围中的元素是string类型。因此,lambda的参数s应该是string&类型,在lambda的函数体中应该取s的地址,用来调用destroy。

for_each(elements, first_free, [this](std::string &s) {alloc.destory(&s);});
作者倾向于for_each和lambda版本,因为这个版本只需指出范围及对范围中元素执行什么操作即可,而for版本则需程序员小心控制指针的增减。

练习13.44:编写标准库string类的简化版本,命名为String。你的类应该至少有一个默认构造函数和一个接受C风格字符串指针参数的构造函数。使用allocator为你的String类分配所需内存。

【出题思路】

本题练习定义自己管理内存的类。

【解答】

总体上需要注意的地方与StrVec的定义类似,只不过StrVec管理的元素为string,而String管理的元素为char。配套网站已有完整程序,读者可以尝试自己定义String,然后与配套网站中的代码进行对照。

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-17 11:49:20  更:2021-10-17 11:49:57 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 3:44:30-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码