C++primer学习:拷贝控制(5):动态内存管理类_编写自己的vector

本文介绍了一个简化版本的string向量实现,利用allocator管理内存,并提供了多种操作方法,如push_back、resize等,同时增加了构造函数和优化的free成员函数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

编写自己的简化版本的vector.简化处在于没有使用模板,只用于string.

首先对于内存的管理应该使用allocator类来管理。注意许多成员的公共部分应该定义成私有部分,避免重复代码.

定义几个指针用于指向动态内存的有效元素范围与分配的内存范围.

#include "iostream"
#include "string"
#include "memory"
#include "utility"
#include "map"
#include "vector"
using namespace std;
class StrVec
{
public:
    StrVec() :elements(nullptr), first_free(nullptr), cap(nullptr){}
    StrVec(const StrVec&);//拷贝构造函数
    StrVec& operator=(const StrVec &);//拷贝赋值运算符
    ~StrVec();//析构函数
    void push_back( const string&);
    size_t size() const { return first_free - elements; }//返回大小
    size_t capcity() const { return cap - elements; }//返回分配内存大小
    void reserve(size_t );
    void resize(size_t);
    void resize(size_t,const string&);//重载resize,初始化
    string * begin() const { return elements; }
    string *end() const { return first_free; }

private:
    static allocator<string> alloc;//用来分配管理动态内存
    void check_n_alloc(){ if (size() == capcity()) reallocate(); };//如果内存已满,重新分配新的内存并移动元素
    pair<string *, string *> alloc_n_copy(const string *, const string *);//分配内存并拷贝给定元素到新分配的内存
    void free();//销毁元素并释放动态分配的内存
    void remove_from(size_t);
    void reallocate();//获得更多内存并拷贝已有元素
    void alloc_n_move(size_t);
    string * elements;//指向首元素的指针
    string* first_free;//指向第一个空闲元素
    string* cap;//指向数组尾后位置
};
/*                  public实现部分                     */
void StrVec::resize(size_t new_size)
{
    resize(new_size, string());
}
void StrVec::resize(size_t new_size,const string &s)
{
    if (new_size > size())//新的大小大于原来大小,必须在原来的末尾添加新的元素
    for (size_t i = size(); i != new_size; ++i)
        push_back(s);
    else //新的大小小于原来大小,删除一些元素
        remove_from(size() - new_size);
}

void StrVec::reserve(size_t n)//保留至少大于n的容量
{
    if (n > capcity())//需求大于当前容量,否则返回,不退回内存
        alloc_n_move(n);
}

void StrVec::push_back(const string&s)
{
    check_n_alloc();
    alloc.construct(first_free++, s);//注意迭代器需要自增
}
StrVec::StrVec(const StrVec& S)
{

    auto p = alloc_n_copy(S.begin(), S.end());//拷贝右侧对象的元素
    elements = p.first;
    first_free = cap = p.second;
}
StrVec& StrVec:: operator=(const StrVec& S)
{
    auto p = alloc_n_copy(S.begin(), S.end());
    free();
    elements = p.first;
    first_free = cap = p.second;
    return *this;
}
StrVec::~StrVec()//析构函数
{
    free();
}
    /****************              private:      ***********************                     */
void StrVec::reallocate()//重新分配内存并移动原来的元素
{
    auto newcapcity = size() ? 2 * size() : 1;
    alloc_n_move(newcapcity);
}
void StrVec::free()
{
    if (elements)//elements不为空
    {
        for (auto p = first_free; p != elements;)//按照递减的方式删除元素
            alloc.destroy(--p);
        alloc.deallocate(elements, capcity());//释放内存
    }
}
void StrVec::remove_from(size_t n)//删除后面的n个元素,不需要释放内存
{
    for (auto p = first_free; p != first_free - n;)//按照递减的方式删除元素
        alloc.destroy(--p);
}
void StrVec::alloc_n_move(size_t newcapcity)
{
    auto newdata = alloc.allocate(newcapcity);//分配比原来大2倍的空间,注意原来的空间内存为0的特殊情况
    auto dest = newdata;
    auto elem = elements;
    for (size_t i = 0; i != size(); ++i)
        alloc.construct(dest++, std::move(*elem++)); //通过size()次循环将元素移动
    free();//释放旧的内存空间
    elements = newdata;
    first_free = dest;
    cap = newdata + newcapcity;
}
pair<string *, string *> StrVec::alloc_n_copy(const string * b, const string * e)
{
    auto data = alloc.allocate(e - b);//分配内存
    return{ data, uninitialized_copy(b, e, data) };//返回第一个迭代器和最后一个迭代器
}

 allocator<string> StrVec:: alloc;//在类外定义静态变量
int main()
{
    StrVec s;   
    s.reserve(5);
    s.push_back("ssss");
    s.push_back("aaaa");
    s.push_back("mmmmmmmm");
    s.resize(10, "xxx");
    for (auto beg = s.begin(); beg != s.end(); ++beg)
        cout << *beg << endl;
    return 0;
}

======================================================================================

增加一个构造函数,用initializer_list作为参数.
StrVec::StrVec(initializer_list<string> il)
{
    for (auto s : il)
        push_back(s);
}
======================================================================================================================
重写free成员,用for_each和lambada来代替for循环,哪种实现更好?
for_each(elements, first_free,[](const string  p){alloc.destroy(&p);});

我认为第二种`更好,因为不需要估计递增与递减。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值