关闭

重新学习《C++Primer5》第12章-动态内存

408人阅读 评论(0) 收藏 举报
分类:

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

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:13044次
    • 积分:409
    • 等级:
    • 排名:千里之外
    • 原创:29篇
    • 转载:1篇
    • 译文:0篇
    • 评论:1条
    最新评论