C ++ Primer quinto notas (capítulo 13 control de copia) Ejemplo 2 gestión de memoria

1. Objetivo

Implemente una versión simplificada de la clase de vector de biblioteca estándar, que solo admite cadenas, la llamamos StrVec.

2. Ideas de diseño

2.1 El asignador administra la reserva de memoria de cada objeto StrVec, que es una memoria contigua (una matriz de tipos). Elementos utilizados para construir insertos de almacenamiento.

push_back插入元素, 检查内存池是否够用?
 . 够用,在内存池的下—可用位置构造对象·
 . 不够用,重组空间: 
   	  . allocator获取全新的更大的内存池
      . 将已有元素拷贝至新的内存池
      . 释放旧的内存池
      . 在新内存池的下—可用位置构造新加入的元素

Inserte la descripción de la imagen aquí

2.2 Cuatro funciones de la herramienta:

alloc_n_copy asignará memoria y copiará los elementos en un rango dado.
el libre albedrío destruye el elemento construido y libera la memoria.
chk.
reasignar asigna nueva memoria para StrVec cuando la memoria se agota.

3. StrVec.h

class StrVec {
    
    
public:
	// copy control members
    StrVec(): 
	  elements(nullptr), first_free(nullptr), cap(nullptr) {
    
     }

	StrVec(const StrVec&);            // copy constructor
	StrVec &operator=(const StrVec&); // copy assignment

#ifdef NOEXCEPT
	StrVec(StrVec&&) noexcept;            // move constructor
	StrVec &operator=(StrVec&&) noexcept; // move assignment
	~StrVec() noexcept;                   // destructor
#else
	StrVec(StrVec&&) throw();            // move constructor
	StrVec &operator=(StrVec&&) throw(); // move assignment
	~StrVec() throw();                   // destructor
#endif

#ifdef INIT_LIST
	// additional constructor
	StrVec(std::initializer_list<std::string>);
#else // define a constructor that takes pointers to a range of elements
	StrVec(const std::string*, const std::string*);
#endif

    void push_back(const std::string&);  // copy the element
    void push_back(std::string&&);       // move the element

	// add elements
    size_t size() const {
    
     return first_free - elements; }
    size_t capacity() const {
    
     return cap - elements; }

	// iterator interface
	std::string *begin() const {
    
     return elements; }
	std::string *end() const {
    
     return first_free; }
    
#ifdef INIT_LIST   // no real substitute for initializer_list in assignments
	// operator functions covered in chapter 14
	StrVec &operator=(std::initializer_list<std::string>);   
#endif

	std::string& operator[](std::size_t n) 
		{
    
     return elements[n]; }

	const std::string& operator[](std::size_t n) const 
		{
    
     return elements[n]; }
	
#ifdef VARIADICS    // no direct substitute for variadic functions
	// emplace member covered in chapter 16
	template <class... Args> void emplace_back(Args&&...);
#endif
private:
    static std::allocator<std::string> alloc; // allocates the elements

	// utility functions:
	//  used by members that add elements to the StrVec
	void chk_n_alloc() 
		{
    
     if (size() == capacity()) reallocate(); }
    // used by the copy constructor, assignment operator, and destructor
	std::pair<std::string*, std::string*> alloc_n_copy
	    (const std::string*, const std::string*);
	void free();             // destroy the elements and free the space
    void reallocate();       // get more space and copy the existing elements
    std::string *elements;   // pointer to the first element in the array
    std::string *first_free; // pointer to the first free element in the array
    std::string *cap;        // pointer to one past the end of the array
};


#include <algorithm>

inline
#ifdef NOEXCEPT
StrVec::~StrVec() noexcept {
    
     free(); }
#else
StrVec::~StrVec() throw() {
    
     free(); }
#endif

4. StrVec.cpp

inline
std::pair<std::string*, std::string*> 
StrVec::alloc_n_copy(const std::string *b, const std::string *e)
{
    
    
	// allocate space to hold as many elements as are in the range
	auto data = alloc.allocate(e - b); 

	// initialize and return a pair constructed from data and
	// the value returned by uninitialized_copy
#ifdef LIST_INIT
	return {
    
    data, uninitialized_copy(b, e, data)};
#else
	return make_pair(data, uninitialized_copy(b, e, data));
#endif
}

inline
#ifdef NOEXCEPT
StrVec::StrVec(StrVec &&s) noexcept  // move won't throw any exceptions
#else
StrVec::StrVec(StrVec &&s) throw()   // move won't throw any exceptions
#endif
  // member initializers take over the resources in s
  : elements(s.elements), first_free(s.first_free), cap(s.cap)
{
    
    
	// leave s in a state in which it is safe to run the destructor
	s.elements = s.first_free = s.cap = nullptr;
}

inline StrVec::StrVec(const StrVec &s)
{
    
    
	// call alloc_n_copy to allocate exactly as many elements as in s
	auto newdata = alloc_n_copy(s.begin(), s.end());
	elements = newdata.first; 
	first_free = cap = newdata.second;
}

inline void StrVec::free()
{
    
    
    // may not pass deallocate a 0 pointer; if elements is 0, there's no work to do
	if (elements) {
    
    
    	// destroy the old elements in reverse order
		for (auto p = first_free; p != elements; /* empty */)
			alloc.destroy(--p);  
		alloc.deallocate(elements, cap - elements);
	}
}
	
#ifdef INIT_LIST
inline StrVec &StrVec::operator=(std::initializer_list<std::string> il)
{
    
    
	// alloc_n_copy allocates space and copies elements from the given range
	auto data = alloc_n_copy(il.begin(), il.end());
	free();   // destroy the elements in this object and free the space
	elements = data.first; // update data members to point to the new space
	first_free = cap = data.second;
	return *this;
}
#endif 

inline
#ifdef NOEXCEPT
StrVec &StrVec::operator=(StrVec &&rhs) noexcept
#else
StrVec &StrVec::operator=(StrVec &&rhs) throw()
#endif
{
    
    
	// direct test for self-assignment
	if (this != &rhs) {
    
    
		free();                   // free existing elements 
		elements = rhs.elements;  // take over resources from rhs
		first_free = rhs.first_free;
		cap = rhs.cap;
		// leave rhs in a destructible state
		rhs.elements = rhs.first_free = rhs.cap = nullptr;
	}
	return *this;
}

inline StrVec &StrVec::operator=(const StrVec &rhs)
{
    
    
	// call alloc_n_copy to allocate exactly as many elements as in rhs
	auto data = alloc_n_copy(rhs.begin(), rhs.end());
	free();
	elements = data.first;
	first_free = cap = data.second;
	return *this;
}

inline void StrVec::reallocate()
{
    
    
    // we'll allocate space for twice as many elements as the current size
    auto newcapacity = size() ? 2 * size() : 1;

  // allocate new memory
	auto newdata = alloc.allocate(newcapacity);

 // move the data from the old memory to the new
	auto dest = newdata;  // points to the next free position in the new array
       auto elem = elements; // points to the next element in the old array
	for (size_t i = 0; i != size(); ++i)
		alloc.construct(dest++, std::move(*elem++));

	free();  // free the old space once we've moved the elements

    // update our data structure to point to the new elements
    elements = newdata;
    first_free = dest;
    cap = elements + newcapacity;
}

#ifdef INIT_LIST
inline StrVec::StrVec(std::initializer_list<std::string> il)
{
    
    
	// call alloc_n_copy to allocate exactly as many elements as in il
	auto newdata = alloc_n_copy(il.begin(), il.end());
	elements = newdata.first;
	first_free = cap = newdata.second;
}
#else
inline StrVec::StrVec(const std::string *b, const std::string* e)
{
    
    
	// call alloc_n_copy to allocate exactly as many elements as in the range
	auto newdata = alloc_n_copy(b, e);
	elements = newdata.first;
	first_free = cap = newdata.second;
}
#endif

inline void StrVec::push_back(const std::string& s)
{
    
    
    chk_n_alloc(); // ensure that there is room for another element
    // construct a copy of s in the element to which first_free points
    alloc.construct(first_free++, s);  
}

inline void StrVec::push_back(std::string &&s) 
{
    
    
    chk_n_alloc(); // reallocates the StrVec if necessary
	alloc.construct(first_free++, std::move(s));
}
 
#ifdef VARIADICS    // no direct substitute for variadic functions
// emplace member covered in chapter 16
template <class... Args>
inline void StrVec::emplace_back(Args&&... args)
{
    
    
    chk_n_alloc(); // reallocates the StrVec if necessary
	alloc.construct(first_free++, std::forward<Args>(args)...);
}
#endif

#endif

【referencia】

[1] Código StrVec.h

Supongo que te gusta

Origin blog.csdn.net/thefist11cc/article/details/113914384
Recomendado
Clasificación