【C++】C++避坑经验谈:数组、vector

要给新人培训C++,奈何大家的时间是分散的,所以在这里开坑写文章了。这里只是个人经验,如果我也坑了的话请勿喷。

一、指针和数组很危险?
  流行的说法是C++尽量不要用指针和数组。指针会出现各种bug。当然只是说尽量不要用,不是说不用。在小型项目和追求速度的项目中,用指针并没有太大问题。注意释放并置零指针、不要用悬垂指针、避免数组越界,指针用起来并没有太大问题。但是遇到中大型项目,经验丰富的程序员会出现指针错误使用的情况,是很正常。
  在项目中,我们会尽量减少指针使用,比如:函数传参使用引用传递;使用智能指针;仿照STL的迭代器,对指针进行包裹。
  注意的是,如果只是临时使用指针,很快就会处理掉这个指针的话,用一用根本无关紧要,不能实行教条主义。另外需要注意的是,智能指针std::shared_ptr包含的两个对象,如果对象内部有指向对方的std::shared_ptr指针,是会出错的,原因可以从std::shared_ptr的实现——引用计数中去思考。按照传统的方法,相互指向对方的指针,其中一方可以使用std::shared_ptr指针,另一方需要使用std::weak_ptr指针。在开源三维图像库VTK中,vtk的两大类对象集合:processObject和dataObject内部有相互指向对方的指针。VTK是processObject包含指向dataObject的智能指针,dataObject内部直接使用指向processObject的普通指针。这是一种合理的方法。

二、图像存储用数组还是std::vector?
  官方的说法是多用std::vector。然而对于图像处理的程序员来说,图像数据应该使用数组来存储。
  Debug模式用来进行程序调试,寻找详细的出错信息;Release模式可以用glog日志、printf输出代码信息等方法来获取出错信息,但明显不如Debug模式靠谱。release程序的std::vector有时候可以达到原生数组的速度,一些第三方STL库内部就是用数组来实现std::vector的;然而在Debug模式下,各平台上std::vector比数组慢多了。图像处理程序中,快速遍历图像是基本操作之一,如果我们要用Debug模式调试程序,显然用遍历std::vector存储的图像,会慢的发狂。因此对于追求速度的一些实现,数组是优先选择。
  然而前面说了,C++要少用普通指针。因此我们一般需要用C++类对指向图像数据的数组进行包裹。OpenCV库的C和C++模式分别使用lpImage和Mat两种数据格式,其中lpImage是用C-struct结构体对图像数据指针和其他信息的包装,但是依然需要使用专门的函数来删除它;Mat是基于C++ 类class/struct封装的图像数据,使用方法跟基本数据类型如int一样,基本无需关心指针和内存方面的问题。C++类使用构造函数来自动创建图像数组和相关信息,析构函数可以在退出作用域时自动调用来删除数据。这使得C++可以构造资源管理类来管理大量的数据。
  PS:在C++中,struct和class的区别在于,struct没有指定的成员都是public,而class没有指定的成员都是private;C++的struct包含默认构造函数和默认析构函数,而C语言的struct仅仅是一个数据集合,两者是不同的。

三、std::vector什么时候使用?
  与之相关的问题是:如何选择STL的容器?
  从问题二中我们看到,std::vector不能用在需要高速读写遍历的情况下。除去上面的情况,在不需要频繁插入删除数据序列头部和中间元素的情况下,不需要使用关联容器的情况下,数组统统用std::vector来实现。
  std::vector有强大的错误检查,用lazy-operation来实现快速尾部数据扩容。在基本确定数据数量的情况下,我们可以使用resize/reserve函数来预分配内存,提高速度。另外如果只是少量的中间数据的插入、删除,std::vector的速度并没有想象中那么差,无需顾忌书中说的std::vector在中间数据的操作性能很不好啊之类的。
  下面这种情况,我们基本可以忽略std::vector对中间数据操作性能很差的特性,看如下代码(C++11):
  
vector<vector<double> > a;
for (int i = 0; i < 7; ++i) {
vector<double> b = { i+0.1, i+0.2, i+0.3 };
a.push_back(b);
}
cout << a.size() << endl;
double *p = &a[4][1];
cout <<p << ":" <<*p << endl;
a.erase(a.begin());
a.erase(a.begin());
cout << a.size() << endl;
cout << p << ":" << *p << endl;
  

输出结果为:
7
00000000002B6B28:4.2
5
00000000002B6B28:4.2
这说明嵌套vector,外层vector保存的是内层vector的指针引用,在删除内层vector元素时,外层vector只是删除了指向内层vector的指针引用并调用了该内层vector元素的析构函数,其他内层vector元素在内存中的位置根本就没有动,因此性能开销不大,可以放心用。

  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值