一直对函数中是否应该直接返回vector有疑惑,今日总算动手测试了一番。大体是设计一个对象,其内存有一个数组,改变这个数组的存储方式,测试其赋值构造函数+循环取数的性能。其中,顺便测试了一下C++11移动语义的效率。大致分了一下情景(代码间后):
- A:使用vector<int>保存内部数据,深拷贝,不使用reserve预先调整vector空间
- A1:使用vector<int>保存内部数据,深拷贝,使用reserve预先调整vector空间
- B:使用shared_ptr<vector<int> >保存内部数据,浅拷贝
- C:使用vector<int> * 保存内部数据,深拷贝
- D:使用vector<int> * 保存内部数据,深拷贝,实现C++11移动语义
- E:使用int *保存内部数据,深拷贝,循环赋值
- E1:使用int *保存内部数据,深拷贝,循环赋值,C++移动语义
- E2:使用int *保存内部数据,深拷贝,memcpy
- E3:使用int *保存内部数据,深拷贝,memcpy,C++移动语义
结果发现使用shared_ptr并非想象中的能加快速度(赋值构造时不需要赋值vector)。这种情况下shared_ptr的好处就只是节省内存了。通过结果比较大致的结论如下:
- 如果预先知道数据的大小,使用vector中的reserve事先调整vector的容量,速度提升非常明显
- 直接使用vector(配合reserve)并不比使用shared_ptr慢,所以在不需要考虑节省内存的情况下(shared_ptr是浅拷贝),直接使用vector,即使做为函数返回值,速度也是相当的。(甚至,在MSVC中,shared_ptr更慢!)
- 在不考虑线程安全的情况下,追求极限速度,还是直接使用原始指针吧
具体测试的结果如下,其中“未优化”是指关闭编译器优化,“编译优化”中msvc11使用“/O2”、g++(4.8)使用“-O3”编译选项:
具体数据:
未优化:
类别 | MSVC11 | G++ |
A | 13.264 | 11.093 |
A1 | 12.471 | 10.873 |
B | 15.138 | 12.482 |
C | 12.867 | 11.412 |
D | 12.862 | 11.261 |
E | 6.485 | 5.438 |
E1 | 3.907 | 3.347 |
E2 | 4.017 | 3.451 |
E3 | 3.767 | 3.348 |
编译优化:
类别 | MSVC11 /O2 | G++ -O3 |
A | 2.491 | 1.536 |
A1 | 1.711 | 0.9417 |
B | 1.877 | 0.9137 |
C | 2.018 | 1.2394 |
D | 1.893 | 0.9334 |
E | 0.96 | 0.6702 |
E1 | 0.572 | 0.36 |
E2 | 0.715 | 0.4476 |
E3 | 0.561 | 0.359 |
测试代码如下:
博客主题和代码加亮插件配合有问题,用链接里的看吧
https://github.com/fasiondog/temp/blob/master/test-1/test.cpp
[cpp]
//使用vector保存数据,深拷贝,不使用reserve
class A {
public:
A(int n) {
for (int i = 0; i < n; ++i) {
_list.push_back(i);
}
}
A(const A& x) {//: _list(x._list) {
//std::cout << “A(const A& x)” << std::endl;
_list = x._list;
}
virtual ~A() {}
size_t size() const { return _list.size(); }
int operator[](int i) const { return _list[i];}
private:
std::vector _list;
};
//使用vector保存数据,深拷贝,使用reserve
class A1 {
public:
A1(int n) {
_list.reserve(n);
for (int i = 0; i < n; ++i) {
_list.push_back(i);
}
}
A1(const A1& x) {// : _list(x._list) {
//std::cout << “A1(const A1& x)” << std::endl;
_list = x._list;
}
virtual ~A1() {}
size_t size() const { return _list.size(); }
int operator[](int i) const { return _list[i];}
private:
std::vector _list;
};
//使用shared_ptr<vector >保存内部数据,浅拷贝,reserve
class B {
public:
B(int n) {
_plist = std::shared_ptr<std::vector >(new std::vector);
_plist->reserve(n);
for (int i = 0; i < n; ++i) {
_plist->push_back(i);
}
}
B(const B& x) { //: _plist(x._plist) {
//std::cout << “B(const B& x)” << std::endl;
_plist = x._plist;
}
virtual ~B() {}
size_t size() const { return _plist->size(); }
int operator[](int i) const { return (*_plist)[i];}
private:
std::shared_ptr<std::vector > _plist;
};
//使用vector * 保存内部数据,深拷贝,reserve
class C {
public:
C(int n) {
_plist = new std::vector;
_plist->reserve(n);
for (int i = 0; i < n; ++i) {
_plist->push_back(i);
}
}
C(const C& x) {
//std::cout << “C(const C& x)” << std::endl;
_plist = new std::vector;
(*_plist) = (*x._plist);
/*_plist->reserve(x.size());
size_t total = x.size();
for (int i = 0; i < total; ++i) {
_plist->push_back(x[i]);
}*/
}
virtual ~C() { delete _plist; }
size_t size() const { return _plist->size(); }
int operator[](int i) const { return (*_plist)[i];}
private:
std::vector *_plist;
};
//使用vector * 保存内部数据,深拷贝,reserve,实现C++11移动语义
class D {
public:
D(int n) {
_plist = new std::vector;
_plist->reserve(n);
for (int i = 0; i < n; ++i) {
_plist->push_back(i);
}
}
D(const D& x) {
std::cout << “D(const D& x)” << std::endl;
_plist = new std::vector;
(*_plist) = (*x._plist);
/*_plist->reserve(x.size());
for (int i = 0; i < x.size(); ++i) {
_plist->push_back(x[i]);
}*/
}
D(D&& x) { //: _plist(x._plist) {
//std::cout << “D(D&& x)” << std::endl;
_plist = x._plist;
x._plist = 0;
}
virtual ~D() { delete _plist; }
size_t size() const { return _plist->size(); }
int operator[](int i) const { return (*_plist)[i];}
private:
std::vector *_plist;
};
//使用int *保证内部数据,深拷贝
class E {
public:
E(int n):_size(n) {
_plist = new int[n];
for (int i = 0; i < n; ++i) {
_plist[i] = i;
}
}
E(const E& x):_size(x._size) {
//std::cout << “E(const E& x)” << std::endl;
_plist = new int[_size];
std::memcpy(_plist, x._plist, x._size * sizeof(int));
/*for (int i = 0; i < x.size(); ++i) {
_plist[i] = x[i];
}*/
}
#if 1
E(E&& x): _size(x._size), _plist(x._plist) {
//std::cout << “E(E&& x)” << std::endl;
x._plist = 0;
}
#endif
virtual ~E() { delete[] _plist; }
size_t size() const { return _size; }
int operator[](int i) const { return _plist[i];}
private:
size_t _size;
int *_plist;
};
template
T func(int n) {
T result(n);
if (n <= 1) { //此处只用<,会被msvc优化掉
//std::cout << “T Func” << std::endl;
return T(1);
}
return result;
}
///编译时,需注意编译器优化NRO
int main() {
unsigned long long t1=0, t2=0;
int max = 50000;
for (int i = 1; i < max; ++i) {
//A a = func(i);
//A1 a = func(i);
//B a = func(i);
//C a = func(i);
//D a = func(i);
E a = func(i);
for (int j = 1; j < a.size(); ++j) {
t1 += a[j];
}
//t1 += a.size();
}
std::cout << t1 << std::endl;
}
[/cpp]