重新學習《C++Primer5》第12章-動態記憶體
阿新 • • 發佈:2019-02-01
12.1動態記憶體與智慧指標
12.1.1 shared_ptr類
1.智慧指標也是模板,定義方式一樣
2.make_shared<>最安全的分配和呼叫方法
auto p=make_shared<vector<string>>();//指向一個動態分配的空vector
3.引用計數
auto r=make_shared<int>(42);
r=q;//遞增q指向的物件的引用計數;遞減r指向的引用計數
4.StrBlob類
- StrBlob.h
#ifndef STRBLOB_H
#define STRBLOB_H
#include<vector>
#include<string>
#include<initializer_list>
#include<memory>
#include<stdexcept>
using namespace std;
class StrBlobPtr;
class StrBlob
{
friend class StrBlobPtr;
friend bool operator==(const StrBlob&, const StrBlob&);
public:
typedef vector<string> ::size_type size_type;
StrBlob();
StrBlob(initializer_list<string> il);
StrBlob(vector<string> *p) :data(p){}
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;
string& operator[](size_t i){ return data[i]; }
/*StrBlobPtr begin();
StrBlobPtr end();*/
~StrBlob();
private:
shared_ptr<vector<string>> data;
void check(size_type i, const string& msg) const;
};
#endif
- StrBlob.cpp
#include "StrBlob.h"
StrBlob::StrBlob() :data(make_shared<vector<string>>()){}
StrBlob::StrBlob(initializer_list<string> il) : data(make_shared<vector<string>>(il)){}
void StrBlob::check(size_type i, const string &msg) const
{
if (i >= data->size())
throw out_of_range(msg);
}
string& StrBlob::front()
{
check(0, "front on empty StrBlob");
return data->front();
}
const string& StrBlob::front() const
{
check(0, "front on empty StrBlob");
return data->front();
}
string& StrBlob::back()
{
check(0, "back on empty StrBlob");
return data->back();
}
const 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();
}
//StrBlobPtr StrBlob::begin()
//{
// return StrBlobPtr(*this);
//}
//StrBlobPtr StrBlob::end()
//{
// auto ret= StrBlobPtr(*this,data->size());
// return ret;
//}
StrBlob::~StrBlob()
{
}
12.1.2直接管理記憶體
1.使用new動態分配和初始化物件
int *p1=new int;//p指向未初始化int物件
int *p2=new int(2);//指,向2
string *s=new string(9,'9');//指向"9999999999"
vector<int> *pv=new vector<int>{1,2,3};
2.使用auto,只有括號僅有單一初始化器才能使用
auto p=new auto(obj);//p指向obj型別
auto p=new auto{a,b,c};//錯誤
3.動態分配const
const int *pci=new const int(1024);
const string *psc=new const string;
4.記憶體耗盡
int *p2=new (nothrow) int;//如果分配失敗,new返回空指標,bad_alloc和nothrow都定義在new標頭檔案中
5.指標值和delete
6.使用new和delete三個常見問題
- 忘記delete記憶體,導致記憶體洩漏
- 使用已經釋放掉的記憶體
- 同一塊記憶體釋放兩次
7.習題
vector<int>* f1()
{
return new vector<int>;
}
shared_ptr<vector<int>> f11()
{
return make_shared<vector<int>>();
}
void f2()
{
vector<int> *pv = f1();
int a;
while (cin >> a)
{
pv->push_back(a);
}
f3(pv);
delete pv;
}
void f21()
{
auto p = f11();
int a;
while (cin >> a)
{
p->push_back(a);
}
}
void f3(vector<int> *pv)
{
for (const auto &e : *pv)
cout << e;
}
void f31(shared_ptr<vector<int>> p)
{
for (const auto &a : *p)
cout << a;
}
12.1.3 shared_ptr和new結合使用
1.
shared_ptr<int> p1=new int(1024);//錯誤
shared_ptr<int> p2(new int(1024));//正確:使用了直接初始化
2.普通指標與智慧指標混淆
- 使用一個內建指標訪問一個智慧指標所負責的物件是危險的,因為無法知道物件何時被銷燬
3.不用使用get初始化另一個智慧指標
- get用在我們需要向不能使用智慧指標的程式碼傳遞一個內建指標
shared_ptr<int> p(new int(42));
int *q=p.get();//OK
4.reset操作
12.1.4 智慧指標和異常
防止智慧指標陷阱規範
- 不使用相同的內建指標初始化多個智慧指標
- 不delete get()返回的指標
- 不使用get()初始化或reset另一個智慧指標
- 如果使用了get(),記住當最後一個對應的智慧指標銷燬後,你的指標就變為無效了
- 如果使用只能指標管理的資源不是new分配的記憶體,記住傳遞給它一個刪除器
shared_ptr<connection> p(&c,end_connection);
12.1.4 unique_ptr
1.使用unique_ptr必須採用直接初始化形式
2.不能拷貝或賦值unique_ptr,但可以呼叫release和reset轉移
unique_ptr<string> p2(p1.release());//將所有權權從p1轉移給p2
unique_ptr<string> p3(new string("Telsa"));
p2.reset(p3.release);//將所有權從p3轉移到p2
3.傳遞unique_ptr引數和返回unique_ptr
//雖然不能拷貝,但是對於即將銷燬的unique_ptr可以
unique_ptr<int> clone(int p)
{
return unique_ptr<int>(new int(p));
}
4.向unique_ptr傳遞刪除器
//過載刪除器時,需要在尖括號內指定刪除器型別
unique_ptr<connnection,decltype(end_connection)*> p(&c,end_connection);
12.1.6 weak_ptr
1.使用shared_ptr初始化,但不會改變引用計數
auto p=make_shared<int>(42);
weak_ptr<int> wp(wp);
2.使用lock返回shared_ptr
shared_ptr<int> np=wp.lock();
3.StrBlobPtr類
- StrBlobPtr.h
#pragma once
#include"StrBlob.h"
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();
~StrBlobPtr();
string& operator[](size_t t){ return (*wptr.lock())[t]; }
private:
shared_ptr<vector<string>> check(size_t, const string&)const;
weak_ptr<vector<string>> wptr;
size_t curr;
};
class IsmorethanN{
public:
IsmorethanN(size_t n) :sz(n){}
bool operator()(const string &s){ return s.size >= sz; }
private:
size_t sz;
};
int main()
{
string s = "sdfsdfsd";
if (IsmorethanN(5)(s))
cout << "yes" << endl;
int sz=5;
auto f = [sz](const string &s){return s.size() >= sz; };
}
- StrBlobPtr.cpp
#include "StrBlobPtr.h"
shared_ptr<vector<string>> StrBlobPtr::check(size_t i, const string &msg)const
{
auto ret = wptr.lock();
if (!ret)
throw runtime_error("unbound strblobptr");
if (i >= ret->size())
throw out_of_range(msg);
}
string& StrBlobPtr::deref()const
{
auto p = check(curr, "dereference past end");
return (*p)[curr];
}
StrBlobPtr& StrBlobPtr::incr()
{
check(curr, "increment past end of StrBlobPtr");
++curr;
return *this;
}
StrBlobPtr& StrBlobPtr::decr()
{
--curr;
check(-1, "decrement past begin of StrBlobPtr");
return *this;
}
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;
}
StrBlobPtr::~StrBlobPtr()
{
}
12.2 動態陣列
12.2.1 new和陣列
1.動態陣列並不是陣列型別,返回的是元素指標
int *pia=new int[10];//10個未初始化的int
string *s=new string[10]();//10個空string
string *sa=new string[2](){"11","22"};
2.動態分配為0
char arr[0];//錯誤
char *arr=new char[0];//正確
3.delete
delete[] pa;//按逆序銷燬元素
4.unique_ptr管理動態陣列
unique_ptr<int[]> up(new int[10]);
up.release();//delete[]
5.使用shared _ptr必須自己定義刪除器
shared_ptr<int> sp(new int[10],[](int *p){delete[] p;});
sp.reset();//會使用自定義delete]
12.2.2 allocator類
1.在memory標頭檔案中,是一個模板
allocator<string> alloc;
auto const p=alloc.allocate(n);
2.allocator分配為構造的記憶體
auto q=p;
alloc.construct(q++);
alloc.construct(q++,10,'c');
alloc.construct(q++,"hi");
3.拷貝和填充未初始化記憶體的演算法
auto p=alloc.allocate(vi.size()*2);
auto q=uninitialized_copy(vi.begin(),vi.end(),p);//通過拷貝vi中的元素來構造從p開始的元素
uninitialized_fill_n(q,vi.size(),42);//剩餘初始化為42
12.3 文字查詢程式
TextQuery.h
#pragma once
#include<map>
#include"QueryResult.h"
#include<fstream>
#include<sstream>
#include<iostream>
//class QueryResult;
class TextQuery
{
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream&);
QueryResult query(const string&);
void display_map();
TextQuery();
~TextQuery();
private:
StrBlob file;
map<string, shared_ptr<set<line_no>>> wm;
string cleamup_str(const string&);
};
TextQuery.h
#pragma once
#include<map>
#include"QueryResult.h"
#include<fstream>
#include<sstream>
#include<iostream>
//class QueryResult;
class TextQuery
{
public:
using line_no = vector<string>::size_type;
TextQuery(ifstream&);
QueryResult query(const string&);
void display_map();
TextQuery();
~TextQuery();
private:
StrBlob file;
map<string, shared_ptr<set<line_no>>> wm;
string cleamup_str(const string&);
};
TextQuery.cpp
#include "TextQuery.h"
using namespace std;
TextQuery::TextQuery()
{
}
TextQuery::TextQuery(ifstream& is) :file(new vector<string>)
{
string text;
while (getline(is, text)){
file.push_back(text);
int n = file.size() - 1;
istringstream line(text);
string word;
while (line >> word){
word = cleamup_str(word);
auto &lines = wm[word];
if (!lines)
lines.reset(new set<line_no>);
lines->insert(n);
}
}
}
string TextQuery::cleamup_str(const string& word)
{
string ret;
for (auto it = word.begin(); it != word.end();++it)
if (!ispunct(*it))
ret += tolower(*it);
return ret;
}
QueryResult TextQuery::query(const string& sought)
{
static shared_ptr<set<line_no>> nodata(new set<line_no>);
auto loc = wm.find(cleamup_str(sought));
if (loc == wm.end())
return QueryResult(sought, nodata, file);
else
return QueryResult(sought, loc->second, file);
}
void TextQuery::display_map()
{
auto iter = wm.cbegin(), iter_end = wm.cend();
for (; iter != iter_end; ++iter){
cout << "word: " << iter->first << " {";
auto text_locs = iter->second;
auto loc_iter = text_locs->cbegin();
auto loc_iter_end = text_locs->cend();
while (loc_iter != loc_iter_end)
{
cout << *loc_iter;
if (++loc_iter != loc_iter_end)
cout << ",";
}
cout << "}\n";
}
cout << endl;
}
TextQuery::~TextQuery()
{
}