您现在的位置是:主页 > news > 都江堰网站建设/云南网站建设快速优化

都江堰网站建设/云南网站建设快速优化

admin2025/5/16 12:04:21news

简介都江堰网站建设,云南网站建设快速优化,如何设计制作一般的企业网站,图片设计网站有哪些C11中大部分的容器对于添加元素除了传统的 insert 或者 pusb_back/push_front 之外都提供一个新的函数叫做 emplace。 比如如果你想要向 std::vector 的末尾添加一个数据&#xff0c;你可以&#xff1a; std::vector<int> nums; nums.push_back(1); 你也可以使用&…

都江堰网站建设,云南网站建设快速优化,如何设计制作一般的企业网站,图片设计网站有哪些C11中大部分的容器对于添加元素除了传统的 insert 或者 pusb_back/push_front 之外都提供一个新的函数叫做 emplace。 比如如果你想要向 std::vector 的末尾添加一个数据&#xff0c;你可以&#xff1a; std::vector<int> nums; nums.push_back(1); 你也可以使用&…

C++11中大部分的容器对于添加元素除了传统的 insert 或者 pusb_back/push_front 之外都提供一个新的函数叫做 emplace。 比如如果你想要向 std::vector 的末尾添加一个数据,你可以:

std::vector<int> nums;
nums.push_back(1);

你也可以使用:

std::vector<int> nums;
nums.empace_back(1);

那么这两种方式的区别到底是什么呢?

避免不必要的临时对象的产生

emplace 最大的作用是避免产生不必要的临时变量,因为它可以完成 in place 的构 造,

优势:在仅传入构造对象的参数时,直接用参数构造对象,不产生临时对象

测试:

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <vector>
using namespace std;class Test{
public:Test(int a = 0) { std::cout << "Test(int a = 0)" << std::endl; }~Test() { std::cout << " ~Test()" << std::endl; }Test(const Test&) { std::cout << "Test(const Test&)" << std::endl; }Test(Test&&) { std::cout << "Test(Test&&)" << std::endl; }
};int main(){Test t1;vector<Test>  v;v.reserve(100);//防止测试中扩容std::cout << "begin-------左值对象" << std::endl;/* 没有区别
begin-------左值对象
Test(const Test&)
Test(const Test&)
end----------------------*/v.push_back(t1);//调用Test(const Test&)v.emplace_back(t1);//调用Test(const Test&)std::cout << "end----------------------" << std::endl;std::cout << "begin-------右值对象" << std::endl;/*  没有区别begin-------右值对象
Test(int a = 0)  临时对象构造
Test(Test&&)  调用右值拷贝构造函数~Test()  //临时对象析构Test(int a = 0)
Test(Test&&)~Test()
end----------------------*/v.push_back(Test(1));//v.emplace_back(Test(2));//std::cout << "end----------------------" << std::endl;std::cout << "begin-------仅仅传入构造函数的参数" << std::endl;/*   区别
begin-------
Test(int a = 0)   push_back 需要构造临时对象
Test(Test&&)~Test()Test(int a = 0)  emplace_back 直接使用参数构造对象
end----------------------*/v.push_back(1);//v.emplace_back(2);//std::cout << "end----------------------" << std::endl;return 0;}

实现

 右值引用     C++11 - 右值引用_大秦坑王的专栏-CSDN博客

函数原型

	template<class... _Valty>decltype(auto) emplace_back(_Valty&&... _Val){	// insert by perfectly forwarding into element at end, provide strong guaranteeif (_Has_unused_capacity()){return (_Emplace_back_with_unused_capacity(_STD forward<_Valty>(_Val)...));}_Ty& _Result = *_Emplace_reallocate(this->_Mylast(), _STD forward<_Valty>(_Val)...);
#if _HAS_CXX17return (_Result);
#else /* ^^^ _HAS_CXX17 ^^^ // vvv !_HAS_CXX17 vvv */(void)_Result;
#endif /* _HAS_CXX17 */}

        利用了c++ 11的新特性变长参数模板(variadic template),直接构造了一个新的对象,不需要拷贝或者移动内存,提高了效率。
        在容器尾部添加一个元素,这个元素原地构造,不需要触发拷贝构造和转移构造。而且调用形式更加简洁,直接根据参数初始化临时对象的成员。

        在c++11中,push_back 在左值引用和右值引用对象中,底层已经使用emplace_back 实现

	void push_back(const _Ty& _Val){	// insert element at end, provide strong guaranteeemplace_back(_Val);}void push_back(_Ty&& _Val){	// insert by moving into element at end, provide strong guaranteeemplace_back(_STD move(_Val));}

简单的实现:

template<typename... Ty>//函数模板的类型推演 + 引用折叠void emplace_back(Ty && ...val)//可变参{if (full())expand();//move(左值):移动语义,得到右值类型   (int&&)a//forward:类型完美转发,能够识别左值和右值类型_allocator.construct(_last, std::forward<Ty>(val)...);_last++;}
  template<typename... Ty>void construct(T *p, Ty&& ... vals){new (p) T(std::forward<Ty>(vals)...);}

完整代码:


#include <iostream>//容器的空间配置器
template <typename T>
struct Allocator
{T* allocate(size_t size)//只负责内存开辟{return (T*)malloc(sizeof(T) * size);}void deallocate(void *p)//只负责内存释放{free(p);}template<typename... Ty>void construct(T *p, Ty&& ... vals){new (p) T(std::forward<Ty>(vals)...);}void destroy(T *p)//只负责对象析构{p->~T();//~T()代表了T类型的析构函数}
};template <typename T, typename Alloc = Allocator<T>>
class vector//向量容器
{
public:vector(int size = 10)//构造{//_first = new T[size];_first = _allocator.allocate(size);_last = _first;_end = _first + size;}void reserve(size_t size) {}~vector()//析构{//delete[]_first;for (T *p = _first; p != _last; ++p){_allocator.destroy(p);//把_first指针指向的数组的有效元素析构}_allocator.deallocate(_first);//释放堆上的数组内存_first = _last = _end = nullptr;}vector(const vector<T> &rhs)//拷贝构造{int size = rhs._end - rhs._first;//空间大小//_first = new T[size];_first = _allocator.allocate(size);int len = rhs._last - rhs._first;//有效元素for (int i = 0; i < len; ++i){//_first[i] = rhs._first[i];_allocator.construct(_first + i, rhs._first[i]);}_last = _first + len;_end = _first + size;}vector<T>& operator=(const vector<T> &rhs)//赋值运算符重载{if (this == &rhs){return *this;}//delete[]_first;for (T *p = _first; p != _last; ++p){_allocator.destory(p);//把_first指针指向的数组的有效元素析构}_allocator.deallocate(_first);//释放堆上的数组内存int size = rhs._end - rhs._first;//空间大小_first = _allocator.allocate(size);int len = rhs._last - rhs._first;//有效元素for (int i = 0; i < len; ++i){_allocator.construct(_first + i, rhs._first[i]);}_last = _first + len;_end = _first + size;return *this;}template<typename Ty>//函数模板的类型推演 + 引用折叠void push_back(Ty &&val)//Ty CMyString& + && = CMyString&{if (full())expand();//move(左值):移动语义,得到右值类型   (int&&)a//forward:类型完美转发,能够识别左值和右值类型_allocator.construct(_last, std::forward<Ty>(val));_last++;}template<typename... Ty>//函数模板的类型推演 + 引用折叠void emplace_back(Ty && ...val)//可变参{if (full())expand();//move(左值):移动语义,得到右值类型   (int&&)a//forward:类型完美转发,能够识别左值和右值类型_allocator.construct(_last, std::forward<Ty>(val)...);_last++;}void pop_back()//尾删{if (empty()) return;verify(_last - 1, _last);//erase(it); verift(it._ptr, _last);//insert(it,val); verift(it._ptr, _last);//--_last;//不仅要把_last指针--,还需要析构删除的元素--_last;_allocator.destroy(_last);}T back()const//返回容器末尾元素值{return *(_last - 1);}bool full()const{return _last == _end;}bool empty()const{return _first == _last;}int size()const//返回容器中元素个数{return _last - _first;}T& operator[](int index){if (index < 0 || index >= size()){throw "OutOfRangeException";}return _first[index];}//迭代器一般实现成容器的嵌套类型class iterator{public:friend class vector <T, Alloc>;//新生成当前容器某一个位置元素的迭代器iterator(vector<T, Alloc> *pvec = nullptr, T *ptr = nullptr):_ptr(ptr), _pVec(pvec){Iterator_Base *itb = new Iterator_Base(this, _pVec->_head._next);_pVec->_head._next = itb;}bool operator!=(const iterator &it)const{//检查迭代器的有效性if (_pVec == nullptr || _pVec != it._pVec)//迭代器为空或迭代两个不同容器{throw "iterator incompatable!";}return _ptr != it._ptr;}void operator++(){//检查迭代器有效性if (_pVec == nullptr){throw "iterator incalid!";}_ptr++;}T& operator*(){//检查迭代器有效性if (_pVec == nullptr){throw "iterator invalid!";}return *_ptr;}const T& operator*()const{if (_pVec == nullptr){throw "iterator invalid!";}return *_ptr;}private:T *_ptr;//当前迭代器是哪个容器对象vector<T, Alloc> *_pVec;//指向当前对象容器的指针};iterator begin(){return iterator(this, _first);}iterator end(){return iterator(this, _last);}//检查迭代器失效void verify(T *first, T *last){Iterator_Base *pre = &this->_head;Iterator_Base *it = this->_head._next;while (it != nullptr){if (it->_cur->_ptr > first && it->_cur->_ptr <= last){//迭代器失效,把iterator持有的容器指针置nullptrit->_cur->_pVec = nullptr;//删除当前迭代器节点,继续判断后面的迭代器节点是否失效pre->_next = it->_next;delete it;it = pre->_next;}else{pre = it;it = it->_next;}}}//自定义vector容器insert方法实现iterator insert(iterator it, const T &val){//1.这里我们未考虑扩容//2.还未考虑it._ptr指针合法性,假设它合法verify(it._ptr - 1, _last);T *p = _last;while (p > it._ptr){_allocator.construct(p, *(p - 1));_allocator.destroy(p - 1);p--;}_allocator.construct(p, val);_last++;return iterator(this, p);}//自定义vector容器erase方法实现iterator erase(iterator it){verify(it._ptr - 1, _last);T *p = it._ptr;while (p < _last - 1){_allocator.destroy(p);_allocator.construct(p, *(p + 1));p++;}_allocator.destroy(p);_last--;return iterator(this, it._ptr);}
private:T *_first;//起始数组位置T *_last;//指向最后一个有效元素后继位置T *_end;//指向数组空间的后继位置Alloc _allocator;//定义容器的空间配置器对象//容器迭代器失效增加代码struct Iterator_Base{Iterator_Base(iterator *c = nullptr, Iterator_Base *n = nullptr):_cur(c), _next(n) {}iterator *_cur;Iterator_Base *_next;};Iterator_Base _head;void expand()//扩容{int size = _end - _first;//T *ptmp = new T[2*size];T *ptmp = _allocator.allocate(2 * size);for (int i = 0; i < size; ++i){_allocator.construct(ptmp + i, _first[i]);//ptmp[i] = _first[i];}//delete[]_first;for (T *p = _first; p != _last; ++p){_allocator.destroy(p);}_allocator.deallocate(_first);_first = ptmp;_last = _first + size;_end = _first + 2 * size;}
};class Test {
public:Test(int a ) { std::cout << "Test(int a = 0)" << std::endl; }Test(int a,int b ) { std::cout << " Test(int a = 0,int b=0) " << std::endl; }~Test() { std::cout << " ~Test()" << std::endl; }Test(const Test&) { std::cout << "Test(const Test&)" << std::endl; }Test(Test&&) { std::cout << "Test(Test&&)" << std::endl; }
};int main() {Test t1(1);vector<Test>  v;v.reserve(100);//防止测试中扩容std::cout << "begin-------左值对象" << std::endl;/* 没有区别
begin-------左值对象
Test(const Test&)
Test(const Test&)
end----------------------*/v.push_back(t1);//调用Test(const Test&)v.emplace_back(t1);//调用Test(const Test&)std::cout << "end----------------------" << std::endl;std::cout << "begin-------右值对象" << std::endl;/*  没有区别begin-------右值对象
Test(int a = 0)  临时对象构造
Test(Test&&)  调用右值拷贝构造函数~Test()  //临时对象析构Test(int a = 0)
Test(Test&&)~Test()
end----------------------*/v.push_back(Test(1));//v.emplace_back(Test(2));//std::cout << "end----------------------" << std::endl;std::cout << "begin-------仅仅传入构造函数的参数" << std::endl;/*   区别
begin-------
Test(int a = 0)   push_back 需要构造临时对象
Test(Test&&)~Test()Test(int a = 0)  emplace_back 直接使用参数构造对象
end----------------------*/v.push_back(1);//
//  v.push_back(1,2);//v.emplace_back(2);//v.emplace_back(2,3);//std::cout << "end----------------------" << std::endl;return 0;}