1. 程式人生 > >重新學習《C++Primer5》第12章-動態記憶體

重新學習《C++Primer5》第12章-動態記憶體

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()
{
}