本文答案,部分参考于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