C++Primer_课后习题第十二章

本文答案,部分参考于C++ Primer 习题集

前面章节的习题答案

第一章

第二章

第三章

第四章

第五章

第六章

第七章

第八章

第九章

第十章

第十一章

配套的学习资料

https://www.jianguoyun.com/p/DTK5uJgQldv8CBjKv80D

12.1

都是4个

StrBlob中的那个vector是共享的.

12.2

#pragma once
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include<vector>
#include<string>
#include<iostream>
class StrBlob {
public :
	typedef std::vector<std::string>::size_type size_type;
	StrBlob();
	StrBlob(std::initializer_list<std::string> i);
	size_type size() const { return data->size(); }
	bool empty()const { return data->empty(); }
	//添加和删除元素
	void push_back(const std::string& t) { data->push_back(t); }
	void pop_back();
	//元素访问
	std::string& front();
	std::string& back();
	const std::string& front() const;
	const std::string& back() const;
private:
	std::shared_ptr<std::vector<std::string>> data;
	void check(size_type i, const std::string& msg) const;
};
void StrBlob::check(size_type i, const std::string& msg) const {
	if (i >= data->size())
		throw std::out_of_range(msg);
}
std::string& StrBlob::front() {
	//如果vector为空,check为抛出一个异常
	check(0, "front on empty StrBlob");
	return data->front();
}
const std::string &StrBlob::front() const {
	check(0, "front on empty StrBlob");
	return data->front();
}

std::string& StrBlob::back() {
	check(0, "back on empty StrBlob");
	return data->back();
}
const std::string& StrBlob::back() const {
	check(0, "back on empty StrBlob");
	return data->back();
}
void StrBlob::pop_back() {
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
#endif

12.3

不需要,常量StrBlob对象是不应该允许修改共享vector对象内容的.

12.4

我们将check定义为私有成员函数,它只会被StrBlob的成员函数调用,而不会被用户程序调用,因此,我们可以很容易的保证传递给它的i的值符合要求,而不必进行检查.

12.5

未编写一个接受一个初始化列表参数的显示构造函数,意味着可以进行列表向StrBlob的隐式类型转换,在需要StrBlob的地方(如函数的参数) ,可以使用列表进行替换,而且,可以进行拷贝形式初始化m,这令程序编写更为简单方便.

​ 但这种隐式转换并不总是好的,例如,列表中可能并非都是合法的值.再如.对于接受StrBlob的函数,传递给它一个列表,会创建一个临时的StrBlob对象,用列表对其初始化,然后在将其传递给函数,当函数完成后,此对象将被丢弃,再也无法访问了.对于这些情况,我们可以定义显示的构造函数,禁止隐式类型转换.

12.6

#include<iostream>
#include<vector>
using namespace std;
vector<int> *Init() {
	return new vector<int>{ 1,2,3,4 };
}
vector<int> Passby(vector<int> *p) {
	vector<int> t;
	for (auto i : (*p)) {
		t.push_back(i);
	}
	return t;
}
void Print(vector<int> z) {
	for (auto i : z) {
		cout << i << " ";
	}
	cout << endl;
}
int main(void) {
	vector<int>* p = Init();
	Print(Passby(p));
	delete(p);
	return 0;
}

12.7

主要就是Init和 vector *p这里改一下.其他的都差不多.

代码如下:

#include<iostream>
#include<vector>
using namespace std;
shared_ptr<vector<int>> Init() {
	return make_shared<vector<int>>();
}
shared_ptr<vector<int>> print_ints(shared_ptr<vector<int>> p) {
	int v;
	while (cin >> v) {
		p->push_back(v);
	}
	return p;
}
void Print(shared_ptr<vector<int>> z) {
	for (auto i : *z) {
		cout << i << " ";
	}
	cout << endl;
}
int main(void) {
	auto p = Init();
	Print(print_ints(p));
	return 0;
}

输入输出如下:

1 2 3 4 5 6 ^Z
1 2 3 4 5 6

12.8

因为这个返回的是根据类型转换而不是自己指定的.

最好是通过捕获异常或是判断返回的指针来返回true或false,而不是依赖类型转换.

12.9

1 会造成内存泄漏,

2 会有一个空悬指针的问题

12.10

这个是正确的.

利用p创建一个临时的shared_ptr赋予process的参数ptr,p和ptr都指向相同的int对象,引用计数被正确的置为2,process执行完毕后,ptr被销毁,引用计数减一.这是正确的.只有p指向它.

12.11

p.get() 获得一个普通指针,指向p所共享的int对象,利用此指针创建一个shared_ptr,而不是利用p创建一个shared_ptr,将不会形成正确的动态共享.编译器会认为p和ptr是使用两个地址(但是它们的地址是相等的).两者的引用计数都是1.processs执行完毕后,临时对象ptr的引用计数为0,管理的内存地址被释放.

​ 但是因为p和ptr的地址是一样的.p的地址就是一个空悬指针了.

12.12

(a) 合法,引用计数一开始是1,在程序中是2,程序结束减一 还是1

(b) 合法,new 创建了一个int对象,指向它的指针被用来创建了一个shared_ptr,程序中引用计数为1,结束了就变为0,ptr被销毁.

©不合法,普通指针不能隐私转换为shared_ptr

(d)合法,但是程序运行会报错.和12.11一样的错误.这里不讲了.

12.13

sp 成为空悬指针.12.11一样的错误.

12.14

#include<iostream>
#include<memory>
using namespace std;
struct destination {};
struct connection{};
connection connect(destination *pd) {
	cout << "打开连接" << endl;
	return connection();
}
void disconnect(connection c) {
	cout << "关闭连接" << endl;
}
//未使用shared_ptr的版本
void f(destination& d) {
	cout << "直接管理connect" << endl;
	connection c = connect(&d);
	//忘记调用disconnect关闭连接
	cout << endl;
}
void end_connection(connection* p) { disconnect(*p); }

//使用shared_ptr的版本
void f1(destination& d) {
	cout << "用shared_ptr管理connect" << endl;
	connection c = connect(&d);
	shared_ptr<connection> p(&c, end_connection);
	//忘记调用disconnect关闭连接
	cout << endl;
}
int main() {
	destination d;
	f(d);
	f1(d);	//f1就算忘记调用了end_connection ,但是只要智能指针使用正确,在程序结束的时候
	//还是会自动调用的
	return 0;
}

输出如下:

直接管理connect
打开连接

用shared_ptr管理connect
打开连接

关闭连接

12.15

就改一行代码.代码如下:

shared_ptr<connection> p(&c, [](connection* p) {disconnect(*p); });

12.16

Severity	Code	Description	Project	File	Line	Suppression State
Error	C2280	'std::unique_ptr<int,std::default_delete<int>> &std::unique_ptr<int,std::default_delete<int>>::operator =(const std::unique_ptr<int,std::default_delete<int>> &)': attempting to reference a deleted function	C++Primer	E:\File\VS\C++Primer\C++Primer.cpp	7	

尝试引用已经删除的函数

我的编译环境是VS2019

错误代码如下:

#include<iostream>
#include<memory>
using namespace std;
int main() {
	unique_ptr<string> p1(new string("Stegosaurus"));
	unique_ptr<string> p2(p1);
	unique_ptr<string> p3;
	p3 = p2;
	return 0;
}

12.17

(a)不合法,unique_ptr需要一个指针来初始化,无法将int转换为指针

(b)合法.但是逻辑上是错误的,p1销毁的时候会时候此内存,结果是未定义的.

© 合法

(d)合法,但是和b的问题相同.

(e)合法

(f)合法,但是有空悬指针的问题.

12.18

因为shared_ptr是可以共享赋值的.

也就是可以拷贝和赋值.不需要release这样的操作.

12.19

这个配套书中的答案,自己观看

/*
 * This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
 * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
 * copyright and warranty notices given in that book:
 *
 * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
 *
 *
 * "The authors and publisher have taken care in the preparation of this book,
 * but make no expressed or implied warranty of any kind and assume no
 * responsibility for errors or omissions. No liability is assumed for
 * incidental or consequential damages in connection with or arising out of the
 * use of the information or programs contained herein."
 *
 * Permission is granted for this code to be used for educational purposes in
 * association with the book, given proper citation if and when posted or
 * reproduced. Any commercial use of this code requires the explicit written
 * permission of the publisher, Addison-Wesley Professional, a division of
 * Pearson Education, Inc. Send your request for permission, stating clearly
 * what code you would like to use, and in what specific way, to the following
 * address:
 *
 * 	Pearson Education, Inc.
 * 	Rights and Permissions Department
 * 	One Lake Street
 * 	Upper Saddle River, NJ  07458
 * 	Fax: (201) 236-3290
*/
#ifndef STRBLOB_H
#define STRBLOB_H

#include "Version_test.h"

#include <vector>
#include <string>
#include <memory>
#include <stdexcept>

#ifdef LIST_INIT
#include <initializer_list>
#endif

// forward declaration needed for friend declaration in StrBlob
class StrBlobPtr;

class StrBlob {
    friend class StrBlobPtr;
public:
    typedef std::vector<std::string>::size_type size_type;

    // constructors
    StrBlob() : data(std::make_shared<std::vector<std::string>>()) { }
#ifdef LIST_INIT
    StrBlob(std::initializer_list<std::string> il);
#else
    StrBlob(std::string*, std::string*);
#endif

    // size operations
    size_type size() const { return data->size(); }
    bool empty() const { return data->empty(); }

    // add and remove elements
    //添加和删除元素
    void push_back(const std::string& t) { data->push_back(t); }
    void pop_back();

    // element access
    //元素访问
    std::string& front();
    std::string& back();

    // interface to StrBlobPtr
    //提供给StrBlobPtr的接口
    StrBlobPtr begin();  // can't be defined until StrBlobPtr is
    StrBlobPtr end();
private:
    std::shared_ptr<std::vector<std::string>> data;
    // throws msg if data[i] isn't valid
    //如果data[i]不合法,抛出一个异常.
    void check(size_type i, const std::string& msg) const;
};

// constructor
#ifdef LIST_INIT
inline
StrBlob::StrBlob(std::initializer_list<std::string> il) :
    data(std::make_shared<std::vector<std::string>>(il)) { }
#else
inline
StrBlob::StrBlob(std::string* b, std::string* e) :
    data(std::make_shared<std::vector<std::string>>(b, e)) { }
#endif

// StrBlobPtr throws an exception on attempts to access a nonexistent element 
class StrBlobPtr {
    friend bool eq(const StrBlobPtr&, const StrBlobPtr&);
public:
    StrBlobPtr() : curr(0) { }
    StrBlobPtr(StrBlob& a, size_t sz = 0) : wptr(a.data), curr(sz) { }

    std::string& deref() const;
    StrBlobPtr& incr();       // prefix version
    StrBlobPtr& decr();       // prefix version
private:
    // check returns a shared_ptr to the vector if the check succeeds
    std::shared_ptr<std::vector<std::string>>
        check(std::size_t, const std::string&) const;

    // store a weak_ptr, which means the underlying vector might be destroyed
    std::weak_ptr<std::vector<std::string>> wptr;
    std::size_t curr;      // current position within the array
};

inline
std::string& StrBlobPtr::deref() const
{
    auto p = check(curr, "dereference past end");
    return (*p)[curr];  // (*p) is the vector to which this object points
}

inline
std::shared_ptr<std::vector<std::string>>
StrBlobPtr::check(std::size_t i, const std::string& msg) const
{
    auto ret = wptr.lock();   // is the vector still around?
    if (!ret)
        throw std::runtime_error("unbound StrBlobPtr");

    if (i >= ret->size())
        throw std::out_of_range(msg);
    return ret; // otherwise, return a shared_ptr to the vector
}

// prefix: return a reference to the incremented object
inline
StrBlobPtr& StrBlobPtr::incr()
{
    // if curr already points past the end of the container, can't increment it
    check(curr, "increment past end of StrBlobPtr");
    ++curr;       // advance the current state
    return *this;
}

inline
StrBlobPtr& StrBlobPtr::decr()
{
    // if curr is zero, decrementing it will yield an invalid subscript
    --curr;       // move the current state back one element}
    check(-1, "decrement past begin of StrBlobPtr");
    return *this;
}

// begin and end members for StrBlob
inline
StrBlobPtr
StrBlob::begin()
{
    return StrBlobPtr(*this);
}

inline
StrBlobPtr
StrBlob::end()
{
    auto ret = StrBlobPtr(*this, data->size());
    return ret;
}

// named equality operators for StrBlobPtr
inline
bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
    auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
    // if the underlying vector is the same 
    if (l == r)
        // then they're equal if they're both null or 
        // if they point to the same element
        return (!r || lhs.curr == rhs.curr);
    else
        return false; // if they point to difference vectors, they're not equal
}

inline
bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs)
{
    return !eq(lhs, rhs);
}
#endif

12.20

代码如下:

#include<iostream>
#include<fstream>
#include "StrBlob.h"
using namespace std;
int main() {
	ifstream in("E:\\File\\HPY\\Zelda.txt");
	if (!in) {
		cout << "无法打开输入文件" << endl;
		return -1;
	}
	StrBlob b;
	string s;
	while (getline(in, s))
		b.push_back(s);
	for (auto it = b.begin(); neq(it, b.end()); it.incr())
		cout << it.deref() << endl;
	return 0;
}

12.21

上面的好,题目给的那个在可读性上,差太多了.

不熟练就容易错.

12.22

我们要未StrBlobPtr定义能接受const StrBlob&参数的构造函数

	StrBlobPtr(const StrBlob & a, size_t sz = 0) :wptr(a.data), curr(sz) {
	}
	StrBlobPtr begin() const;
	StrBlobPtr end() const;
	inline StrBlobPtr StrBlob::begin() const {
		return StrBlobPtr(*this);
	}
	inline StrBlobPtr StrBlob::end() const {
		auto ret = StrBlobPtr(*this, data->size());
		return ret;
	}

12.23

我的理解出了问题,就是用函数算长度,分配一下长度就OK 了.

	const char* c1 = "Link and ";
	const char* c2 = "Zelda";
	char* r = new char[strlen(c1) + strlen(c2)];
	string s1 = "Link and ";
	string s2 = "Zelda";
	char* r = new char[s1.length()+s2.length()];

12.24

#include<iostream>
#include<fstream>
#include "StrBlob.h"
#include<string>
using namespace std;
int main() {
	string s1 = "Link and ";
	string s2 = "Zelda";
	char* r = new char[5];
	string t;
	char c;
	int index = 0;
	while (cin.get(c)) {
		if (isspace(c))
			break;
		r[index++] = c;
		if (index == 5) {
			cout << "容量满了啊" << endl;
			break;
		}
	}
	r[index] = 0;
	cout << r << endl;
	return 0;
}

输入输出

ZeldaLoveLink
容量满了啊
Zelda

12.25

delete [] pa;

12.26

#include<iostream>
#include<string>
#include<memory>
using namespace std;
int main(void) {
	allocator<string> alloc;
	//分配100个未初始化的string
	auto const p = alloc.allocate(100);
	string s;
	string* q = p;
	while (cin >> s && q != p + 100)
		alloc.construct(q++, s);
	const size_t size = q - p;
	//使用数组
	for (size_t i = 0; i < size; ++i)
		cout << p[i] << " " << endl;
	while (q != p)
		alloc.destroy(--q);
	alloc.deallocate(p, 100);
	return 0;
}

12.27+28

TextQuery.h

/*
 * This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
 * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
 * copyright and warranty notices given in that book:
 * 
 * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
 * 
 * 
 * "The authors and publisher have taken care in the preparation of this book,
 * but make no expressed or implied warranty of any kind and assume no
 * responsibility for errors or omissions. No liability is assumed for
 * incidental or consequential damages in connection with or arising out of the
 * use of the information or programs contained herein."
 * 
 * Permission is granted for this code to be used for educational purposes in
 * association with the book, given proper citation if and when posted or
 * reproduced.Any commercial use of this code requires the explicit written
 * permission of the publisher, Addison-Wesley Professional, a division of
 * Pearson Education, Inc. Send your request for permission, stating clearly
 * what code you would like to use, and in what specific way, to the following
 * address: 
 * 
 * 	Pearson Education, Inc.
 * 	Rights and Permissions Department
 * 	One Lake Street
 * 	Upper Saddle River, NJ  07458
 * 	Fax: (201) 236-3290
*/ 

#ifndef TEXTQUERY_H
#define TEXTQUERY_H

#include "Version_test.h"

#include <memory>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <fstream>
#include "QueryResult.h"

/* this version of the query classes includes two
 * members not covered in the book:  
 *   cleanup_str: which removes punctuation and 
 *                converst all text to lowercase
 *   display_map: a debugging routine that will print the contents
 *                of the lookup mape
*/

class QueryResult; // declaration needed for return type in the query function
class TextQuery {
public:
#ifdef TYPE_ALIAS_DECLS
	using line_no = std::vector<std::string>::size_type;
#else
	typedef std::vector<std::string>::size_type line_no;
#endif
	TextQuery(std::ifstream&);
    QueryResult query(const std::string&) const; 
    void display_map();        // debugging aid: print the map
private:
    std::shared_ptr<std::vector<std::string>> file; // input file
    // maps each word to the set of the lines in which that word appears
    std::map<std::string, 
	         std::shared_ptr<std::set<line_no>>> wm;  

	// canonicalizes text: removes punctuation and makes everything lower case
    static std::string cleanup_str(const std::string&);
};
#endif

QueryResult.h

/*
 * This file contains code from "C++ Primer, Fifth Edition", by Stanley B.
 * Lippman, Josee Lajoie, and Barbara E. Moo, and is covered under the
 * copyright and warranty notices given in that book:
 * 
 * "Copyright (c) 2013 by Objectwrite, Inc., Josee Lajoie, and Barbara E. Moo."
 * 
 * 
 * "The authors and publisher have taken care in the preparation of this book,
 * but make no expressed or implied warranty of any kind and assume no
 * responsibility for errors or omissions. No liability is assumed for
 * incidental or consequential damages in connection with or arising out of the
 * use of the information or programs contained herein."
 * 
 * Permission is granted for this code to be used for educational purposes in
 * association with the book, given proper citation if and when posted or
 * reproduced.Any commercial use of this code requires the explicit written
 * permission of the publisher, Addison-Wesley Professional, a division of
 * Pearson Education, Inc. Send your request for permission, stating clearly
 * what code you would like to use, and in what specific way, to the following
 * address: 
 * 
 * 	Pearson Education, Inc.
 * 	Rights and Permissions Department
 * 	One Lake Street
 * 	Upper Saddle River, NJ  07458
 * 	Fax: (201) 236-3290
*/ 

#ifndef QUERYRESULT_H
#define QUERYRESULT_H
#include <memory>
#include <string>
#include <vector>
#include <set>
#include <iostream>

class QueryResult {
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
	typedef std::vector<std::string>::size_type line_no;
	typedef std::set<line_no>::const_iterator line_it;
	QueryResult(std::string s, 
	            std::shared_ptr<std::set<line_no>> p, 
	            std::shared_ptr<std::vector<std::string>> f):
		sought(s), lines(p), file(f) { }
	std::set<line_no>::size_type size() const  { return lines->size(); }
	line_it begin() const { return lines->cbegin(); }
	line_it end() const   { return lines->cend(); }
	std::shared_ptr<std::vector<std::string>> get_file() { return file; }
private:
	std::string sought;  // word this query represents
	std::shared_ptr<std::set<line_no>> lines; // lines it's on
	std::shared_ptr<std::vector<std::string>> file;  //input file
};

std::ostream &print(std::ostream&, const QueryResult&);
#endif

12.29

差不多的

12.30

见 12.27

12.31

因为set是有自动排序的.

vector没有自动排序

12.32

见12.27

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值