WHCSRL 技术网

c++Primer第12章:动态内存与智能指针_nepu

12.1.1节练习

12.1:在此代码的结尾,b1b2各包含多少个元素?

StrBlob b1;
{
	StrBolb b2={"a","b","the"};
	b1=b2;
	b2.push_back("about");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

答:考虑到是智能指针,所以会共享内存,所以都是4个
12.2:编写你自己的StrBlob类,包含const版本的frontback
答:

class StrBlob {
public :
	typedef std::vector<std::string>::size_type size_type;
	StrBlob();
	StrBlob(std::initializer_list<std::string> i1);
	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() const {
		return data->front();
	}
	std::string& back() const {
		return data->back();
	}
private:
	std::shared_ptr<std::vector<std::string>>data;
	void check(size_type i, const std::string& msg) const;

};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

12.3:StrBlob需要const版本的push_backpop_back吗?如果需要,添加进去,否则给出理由
答:不需要,常量对象不允许修改共享对象内容
12.4:在我们的check函数中,没有检查i是否大于0,为什么可以忽略这个检查?
答:因为很容易保证传给它的i值符合要求
12.5:我们未编写接受一个initializer_list explist,参数的构造函数。讨论这个设计的优点和缺点
答:略

12.1.2节练习

12.6:编写函数,返回一个动态分配的intvector传递给另一个函数,这个函数读取标准输入,将读取的值保存在vector中。再将vector传递给另一个函数,打印读入的值。记得在恰当的时刻delete vector
答:

vector<int>* new_vector(void){
	return new vector<int>;
}
void read_ints(vector<int>*pr) {
	int v;
	while (cin >> v) {
		pr->push_back(v);
	}
}
void print_ints(vector<int>* pv) {
	for (const auto& v : *pv) {
		cout << v << " ";
	}
	cout << endl;
}
int main() {
	vector<int>* pv = new_vector();
	if (!pv) {
		cout << " 内存不足" << endl;
		return -1;
	}
	read_ints(pv);
	print_ints(pv);
	delete pv;
	return 0;
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

12.7:重做上一题,这次使用shared_ptr而不是内置指针
答:

shared_ptr<vector<int>>new_vector(void){
	return make_shared<vector<int>>();	
}
void read_ints(shared_ptr<vector<int>>pr) {
	int v;
	while (cin >> v) {
		pr->push_back(v);
	}
}
void print_ints(shared_ptr<vector<int>>pv) {
	for (const auto& v : *pv) {
		cout << v << " ";
	}
	cout << endl;
}
int main() {
	shared_ptr<vector<int>>pv = new_vector();
	if (!pv) {
		cout << " 内存不足" << endl;
		return -1;
	}
	read_ints(pv);
	print_ints(pv);
	cout << pv.unique();
	return 0;
	
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

12.8:下面的函数是否有错误?如果有解释原因

bool b(){
int *p=new int;
//...
return p;
}
  • 1
  • 2
  • 3
  • 4
  • 5

答:没有,因为可以进行强制转换,但是做法不太好
12.9:解释下面代码执行结果

int *q=new int(42),*r=new int(100);
r=q;
auto q2=make_shared<int>(42);
r2=make_shared<int>(1000);
r2=q2;
  • 1
  • 2
  • 3
  • 4
  • 5

答:如果是用new 的话,会有无用的内存无法释放,而智能指针则会自动释放

12.1.3节练习

12.10:下面的代码调用了413页中定义的process函数,解释此函数调用是否正确?

shared_ptr<int>p(new int(42));
process(shared_ptr<int>p());
  • 1
  • 2

答:调用正确
12.11:如果我们像下面这样调用process,会发生什么

process(shared_ptr<int>(p.get()));
  • 1

答:发生了错误,应该是造成了空悬指针
12.12:psp的定义如下,对于接下来的对process的每个调用,如果合法,解释它做了什么,如果不合法,解释错误原因

auto p=new int();
auto sp=make_shared<int>();
(a)process(sp);
(b)process(new int());
(c)process(p)
(d)process(shared_ptr<int>(p));
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

答:a合法,b合法,c不合法,d合法,但会造成空悬指针
12.13:如果执行下面的代码,会发生什么

auto sp=make_shared<int>();
auto p=sp.get();
delete p;
  • 1
  • 2
  • 3

答:智能指针还在,结果内存就释放了,应该会报错

12.1.4

12.14:编写你自己版本用的shared_ptr管理的connection函数
答:

struct destination {};
struct connection {};
connection connect(destination* pd) {
	cout << " 打开连接" << endl;
	return connection();
}
void disconnection(connection c) {
	cout << "关闭连接" << endl;
}
void f(destination& d) {
	cout << "直接管理connection" <<endl;
	connection c = connect(&d);
	cout << endl;
}
void end_connection(connection* p) { disconnection(*p); }
void f1(destination& d) {
	cout << "用shared_ptr管理connect" << endl;
	connection c = connect(&d);
	shared_ptr<connection>p(&c, end_connection);
	cout << endl;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

12.15:重写上一题的程序,用lambda代替end_connection
答:

[](connection*p)->void{ disconnection(*p); }
用这个换入即可
  • 1
  • 2

12.1.5节练习

12.16:如果你试图拷贝或赋值unique_ptr,编译器并不是总能给出易于理解的错误信息。编写包含这样的错误的程序,观察编译器如恶化诊断这种错误
答:自己可以试一下
12.17:下面的unique_ptr声明中,哪些是合法的,哪些可能导致后续的程序错误?解释每个错误的问题在哪里

int ix=1024,*pi=&ix,*pi2=new int(2048);
typedef unique_ptr<int>IntP;
(a)IntP p0(ix)//错误,需要指针初始化
(b)IntP p1(pi)//合法,但是释放内存后,ix会成为空悬指针
(c)IntP p2(pi2)//合法,利用动态分配对象的指针来初始化是正确的
(d)IntP p3(&ix)//合法
(e)IntP p4(new int(2048))//合法
(f)IntP p5(p2.get())//合法,但是会产生空悬指针
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

12.18:shared_ptr为什么没有release成员
答:可以共享内存,不需要

12.1.6节练习

12.19:定义你自己的StrBlobPtr,更新StrBlob类,加入恰当的friend声明和begin()以及end()成员
答:

//全是参考答案的
main.c
#include<iostream>
using namespace std;
#include "my_StrBlob.h"
int main() {
	StrBlob b1;
	{
		StrBlob b2 = { "a","an","end" };
		b1 = b2;
		b2.push_back("about");
		cout << b2.size() << endl;
	}
	cout << b1.size() << endl;
	cout << b1.front() << " " << b1.back() << endl;
	const StrBlob b2 = b1;
	const StrBlob b3 = b1;
	cout << b3.front() << " " << b3.back() << endl;
	for (auto it = b1.begin();neq(it, b1.end());it.incr())
		cout << it.deref() << endl;
	return 0;
}
my_StrBlob.h
#ifndef MY_STRBLOB_H
#define MY_STRBLOB_H
#include<vector>
#include<string>
#include<initializer_list>
#include<stdexcept>
#include<memory>
using namespace std;
class StrBlobPtr;

class StrBlob {
	friend class StrBlobPtr;
public:
	typedef vector<string>::size_type size_type;
	StrBlob();
	StrBlob(initializer_list<string>i1);
	size_type size() const { return data->size(); };
	bool empty() const { return data->empty(); };
	//添加和删除元素
	void push_back(const string& t) { data->push_back(t); };
	void pop_back();
	//元素访问
	string& front();
	const string& front() const;
	string& back();
	const string& back() const;
	
	//提供给StrBlob的接口
	StrBlobPtr begin();
	StrBlobPtr end();
private:
	shared_ptr<std::vector<string>>data;
	//如果data[i]不合法,抛出一个异常
	void check(size_type i, const std::string& msg) const;

};
inline StrBlob::StrBlob() :data(make_shared<vector<string>>()) {};
StrBlob::StrBlob(initializer_list<string>i1) :data(make_shared<vector<string>>(i1)) {};
inline void StrBlob::check(size_type i, const string& msg) const {
	if (i >= data->size())
		throw out_of_range(msg);
}
inline string& StrBlob::front() {
	check(0, "front on empty StrBlob");
	return data->front();
}
inline const string& StrBlob::front() const {
	check(0, "front on empty StrBlob");
	return data->front();
}
inline string& StrBlob::back() {
	check(0, "back on empty StrBlob");
	return data->back();
}
inline const string& StrBlob::back()const {
	check(0, "back on empty StrBlob");
	return data->back();
}
inline void StrBlob::pop_back() {
	check(0, "pop_back on empty StrBlob");
	data->pop_back();
}
//当试图访问一个不存在的元素时,StrBlobPtr抛出一个异常
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) {};
	string& deref() const;
	StrBlobPtr& incr();
	StrBlobPtr& decr();
private:
	shared_ptr<vector<string>>check(size_t, const string&) const;
	weak_ptr<vector<string>>wptr;
	size_t curr;
};
inline shared_ptr<vector<string>>StrBlobPtr::check(size_t i, const string& msg)const {
	auto ret = wptr.lock();
	if (!ret) {
		throw runtime_error("enbound StrBlobPtr");
	}
	if (i >= ret->size())
		throw out_of_range(msg);
	return ret;
}
inline string& StrBlobPtr::deref() const {
	auto p = check(curr, "derefrence past end");
	return (*p)[curr];
}
//前缀递增,返回递增后的对象的引用
inline StrBlobPtr& StrBlobPtr::incr() {
	check(0, "increment past end of StrBlobPtr");
	++curr;	
	return *this;
}
//前缀递减
inline StrBlobPtr& StrBlobPtr::decr() {
	--curr;
	check(-1, "decrement past of begin of StrBlobPtr");
	return *this;
}
inline StrBlobPtr StrBlob::begin() {
	return StrBlobPtr(*this);
}
inline StrBlobPtr StrBlob::end() {
	auto ret = StrBlobPtr(*this, data->size());
	return ret;
}
inline bool eq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {
	auto l = lhs.wptr.lock(), r = rhs.wptr.lock();
	if (l == r) {
		return (!r || lhs.curr == rhs.curr);
	}
	else {
		return false;
	}
}
inline bool neq(const StrBlobPtr& lhs, const StrBlobPtr& rhs) {
	return !eq(lhs, rhs);
}
#endif
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144

12.20:编写程序,逐行读入一个输入文件,将内容存入一个strBlob中,用一个StrBlobPtr打印出StrBlob中的每个元素
答:

int main(){
	ifstream in("D:\text.txt");
	StrBlob b;
	string s;
	while(getline(in,s))
	b.push_back();
	for(auto it=b.begin();neq(it,b.end());it.incr())
	cout<<it.deref()<<endl;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

12.21:略
12.22:略

12.2.1节练习

12.23:编写一个程序,连接两个字符串字面量,将结果保存在一个动态分配的char数组中,连接两个标准string对象
答:

char
 	const char* str1 = "hello";
    const char* str2 = "world";
    auto my_str = new char[40];
    int count = 0;
    for (int i = 0;i < strlen(str1);i++) {
        my_str[count++] = str1[i];
    }
    for (int i = 0;i < strlen(str2);i++) {
        my_str[count++] = str2[i];
    }
    my_str[count] = '';
    cout << my_str << endl;
//string
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
int main()
{
    string str1 = "hello";
    string str2 = "world";
    char* my_str = new char[40];
    strcpy(my_str, (str1 + str2).c_str());
    cout << my_str << endl;
    return 0;
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28

12.24:编写一个程序,从标准输入中读入一个字符串,存入一个动态分配的字符数数组中。
答:

#include<iostream>
#include<cstring>
using namespace std;
int main() {
	string s;
	while (cin >> s) {
		char* str = new char[s.size() + 1];
		strcpy(str, s.c_str());
		cout << str << endl;
	}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

12.25:给定下面的new表达式,你应该如何释放pa

int*pa=new int[10];
  • 1

答:delete [] pa

12.2.2节练习

12.26:用allocator重写427页程序
答:

#include<iostream>
#include<cstring>
#include<memory>
using namespace std;
const int n = 2;
int main() {
	allocator<string>alloc;
	
	auto const p = alloc.allocate(n);
	string s;
	string* q = p;
	while (cin >> s && q != p + n) {
		alloc.construct(q++, s);
	}
	const size_t size = q - p;
	cout << *p << " "<<size << endl;
	while (p != q) {
		alloc.destroy(--q);
	}
	alloc.deallocate(p, n);
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

后言

后几题就不写了,主要都是对所学知识的应用,我实在是不想搞了

推荐阅读