zoukankan      html  css  js  c++  java
  • 交换操作

    通常定义交换,需要一次拷贝和两次赋值:

    Hasptr temp = v1;	//创建v1的一个临时副本
    v1 = v2;		 //将v2赋值给v1
    v2 =temp;		//将保存v1的值赋予v2
    
    

    拷贝一个类值的 Hasptr 会分配一个新的 string 并将其拷贝到 Hasptr 指向的位置,但是更希望 swap 是交换指针,而不是分配 string 的新副本:

    string &temp = v1.ps;
    v1.ps = v2.ps;
    v2.ps = temp.ps;
    
    

    可以在类上自定义一个版本的 swap:

    class HasPtr{
    	friend void swap(HasPtr &lhs,HasPtr &rhs);
    }
    
    inline swap(HasPtr&,HasPtr&)
    {
    	using std::swap;
    	swap(lhs.ps,rhs.ps);	//交换指针,而不是string的数据
    	swap(lhs.i;rhs.i);	//交换int成员
    }
    
    

    与拷贝控制成员不同, swap 并不是必要的。但是,分配了资源的类,定义 swap 可能是一种很重要的优化手段。

    赋值运算符中使用 swap

    定义了 swap 的类通常用 swap 来定义它们的赋值运算符,这些运算符使用了一种名为拷贝并交换的技术,这种技术将左侧运算对象与右侧运算对象的一个副本进行交换。

    rhs 是按值传递的:

    HasPtr& HasPtr::operator=(HasPtr rhs)
    {
    	//交换左侧运算对象和局部变量rhs的内容
    	swap(*this,rhs);
    	return *this;	//rhs 被销毁,从而delete了rhs中的指针
    }
    
    

    注意:

    使用拷贝和交换的赋值运算符自动就是异常安全的,并且能正确处理自赋值。

    动态内存管理类

    某些类需要在运行时分配可变大小的内存空间,这种类通常可以使用标准库容器来保存它们的数据。但是,这个策略并不是对每一个类都适用:某些类需要自己进行内存空间分配,这些类一般来说必须定义自己的拷贝控制成员来管理所分配的内存。

    实现一个 vector 的简化版本,只用于 string

    StrVec 的类设计

    使用 allocator 来获得原始内存,由于 allocator 分配的内存是未构造的。所以添加新元素时,用 alloctorconstruct 成员在原始内存中创建对象。

    当删除一个元素时,使用 destroy 成员来销毁。

    每个 StrVec 有三个指针成员指向其元素所使用的内存:

    • elements,指向分配的内存中的首元素。
    • first_free,指向最后一个实际元素之后的位置。
    • cap,指向分配的内存末尾之后的位置。

    StrVec 还有一个名为 alloc 的静态成员,其类型为 allocator<string>alloc 成员分配 StrVec 使用的内存。

    四个工具函数:

    • alloc_n_copy 会分配内存,并拷贝一个给定范围中的元素。
    • free 会销毁构造元素并释放内存。
    • chk_n_alloc 保证 StrVec 至少有容纳一个新元素的空间,如果没有空间添加新元素,chk_n_alloc 会调用 reallocate 类分配更多的内存。
    • reallocate 在内存用完时为 StrVec 分配新的内存。

    StrVec 类定义

    class StrVec
    {
    public:
    	StrVec():elements(nullptr),first_free(nullptr),cap(nullptr){}
    	StrVec(const StrVec&)
    	StrVec& operator = (const StrVec&);
    	~StrVec();
    	void push_back(const std::string&);
    	size_t size() const {return first_cap - elements;}
    	size_t capacity() const {return cap - elements;}
    	std::string *begin() const {return elements;}
    	std::string *end()const  {return first_free;}
    
    private:
    	static std::allocator<std::string> alloc;
    	void chk_n_alloc()
    	{
    		if(size() == capacity())
    			reallocate();
    	}
    	std::pair<std::string*,std::string*> alloc_n_copy(const std::string*,const std::string*);
    	void free();
    	void reallocate();
    	std::string *elements;
    	std::string *first_free;
    	std::string *cap;
    }
    
    
    void StrVec::push_back(const string& s)
    {
    	chk_n_alloc();	//确保有空间容纳新的元素
    	alloc.construct(first_free++,s);	//在first_free指向的元素中构造s的副本,first_free递增
    }
    
    pair<string*,string*>
    StrVec::alloc_n_copy()(const std::string* b,const std::string* e)
    {
    	//分配空间保存给定范围中的元素
    	auto data =  alloc.allocate(e - b);
    	//初始化并返回一个pair
    	return {data,uninitialize_copy(b,e,data)};
    }
    
    void StrVec::free()
    {
    	if(elements)
    	{
    		//逆序销毁元素
    		for(auto p =first_free;p!=elements;)
    			alloc.destroy(--p);
    		
    		alloc.deallocate(elements,cap - elements);
    	}
    }
    
    StrVec::StrVec(const StrVec &s)
    {
    	auto newdata = alloc_n_copy(s.begin(),s.end());
    	elements =  newdata.first;
    	first_free = cap = newdata.second;
    }
    
    StrVec::~StrVec() { free(); }
    
    StrVec& StrVec::operator= (const StrVec &rhs)
    {
    	auto data = alloc_n_copy(rhs.begin(),rhs.end());
    	free();
    	elements = data.first;
    	first_free = cap = data.second;
    	return *this;
    }
    
  • 相关阅读:
    Light OJ 1030
    Light OJ 1027
    [转]Learn SQLite in 1 hour
    基于 Arduino 的 RFID 识别实验
    RFID 知识的学习
    Arduino UNO R3
    浪潮之巅(第2版)- 读书笔记
    [转]周易入门三十五问答
    Nginx代码风格图示
    封神演义
  • 原文地址:https://www.cnblogs.com/xiaojianliu/p/12496735.html
Copyright © 2011-2022 走看看