赞
踩
C++11中很大的一个特性是移动语义,移动语义可以将资源“偷”过来,避免了资源的拷贝和释放。在类有很大的资源时,使用移动语义可以大幅的提升类构造和赋值的性能。
接下来分析一下,移动语义是如何提升vector性能的。
class A { public: A() { cout << "constuctor :" << this << endl; const char * s = "hello"; int len = strlen(s); str_ = new char[len + 1]; strcpy(str_, s); } A(const A &another) { cout << this << " cpy constructor from " << &another << endl; int len = strlen(another.str_); str_ = new char[len + 1]; strcpy(str_, another.str_); } A(A &&another) noexcept { cout << this << " move constructor from " << &another << endl; this->str_ = another.str_; another.str_ = nullptr; } ~A() { cout << "deconstrutor :" << this << endl; if (str_) { delete[] str_; } } private: char *str_; };
A a;
vector<A> va(3,a);
vector<A> va(3,a);
执行完毕后,vector中有三个元素,且每个元素都有资源。
A a;
vector<A> va(3,a);
cout<<"============================"<<endl;
va.push_back(a);
推入a元素之前,va并没有多余的空间,所以为了存放a元素,需要再开辟一段空间,将a元素推进去,同时还需要将之前的三个元素也拷贝过去。
在拷贝之前的三个元素时,会造成资源的拷贝和释放。
A a;
vector<A> va(3,a);
A a;
vector<A> va(3,a);
cout<<"============================"<<endl;
va.push_back(a);
可以看到,在将旧空间中的三个元素搬移到新空间时,使用的是移动构造而不是拷贝构造。在移动构造时,直接将旧元素的资源给搬移过来了,而没有发生资源的拷贝和释放。
vector的空间在扩容时,需要将旧空间的元素复制到新的空间,使用移动构造,可以将旧空间中,旧元素的资源给“偷”到新空间的元素中,这样就可以避免资源的拷贝和释放,可以极大的提高性能。
A(A &&another) noexcept
{
cout << this << " move constructor from " << &another << endl;
this->str_ = another.str_;
another.str_ = nullptr;
}
移动构造必须加上noexcept,否则vector不会使用移动构造,依然使用拷贝构造。
A a;
vector<A> va(3,a);
cout<<"============================"<<endl;
va.push_back(a);
当A(A &&another)
去掉noexcept后,使用的依然是拷贝构造。
以上截取自《C++性能优化指南》P111。
以上截取自《C++ primer(第五版)》P474。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。