c++Primer第12章:动态内存与智能指针_nepu
12.1.1节练习
12.1:在此代码的结尾,b1
和b2
各包含多少个元素?
StrBlob b1;
{
StrBolb b2={"a","b","the"};
b1=b2;
b2.push_back("about");
}
- 1
- 2
- 3
- 4
- 5
- 6
答:考虑到是智能指针,所以会共享内存,所以都是4个
12.2:编写你自己的StrBlob
类,包含const
版本的front
和back
答:
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_back
和pop_back
吗?如果需要,添加进去,否则给出理由
答:不需要,常量对象不允许修改共享对象内容
12.4:在我们的check
函数中,没有检查i
是否大于0
,为什么可以忽略这个检查?
答:因为很容易保证传给它的i值符合要求
12.5:我们未编写接受一个initializer_list explist
,参数的构造函数。讨论这个设计的优点和缺点
答:略
12.1.2节练习
12.6:编写函数,返回一个动态分配的int
的vector
传递给另一个函数,这个函数读取标准输入,将读取的值保存在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:p
和sp
的定义如下,对于接下来的对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
后言
后几题就不写了,主要都是对所学知识的应用,我实在是不想搞了