[C++]C++学习笔记

1.vector.clear导致vector interator incompatible?

A:首先要明白导致vector iterator incompatible错误的常见原因?比如vector越界访问。

一个比较经典的例子是:

 1 VectorType::iterator it = someVector.begin();

 2 for (; it != someVector.end();)

 3 {

 4     if (*it== value)

 5     {

 6         someVector.erase(it);

 7     }

 8      else

 9     {

10         ++it;

11     }

12 }           

代码中,在erase操作后,没有修改it就继续循环,在与end()比较时,断言出现。

这里的主要问题是,vector可以用任意方法实现erase,不保证在erase一个元素后,后续的元素一定被移动到这个iterator所引用的位置(地址)。当然,这在几乎所有STL的实现中,都是对的,这也就是以前用VC6编译后运行没有问题的原因。但如果这里用的不是vector,而是list或是map,运行到这里,程序会毫不犹豫的崩溃。

正确的做法是这样的:

STL里所有的容器类的erase实现都会返回一个iterator,这个iterator指向了“当前删除元素的后继元素,或是end()”

因此,在遍历容器的所有元素过程中通过erase删除一个元素后,将erase的返回值赋给迭代变量:

 1 VectorType::iterator it = someVector.begin();

 2 for (; it != someVector.end();)

 3 {

 4     if (*it== value)

 5     {

 6         it = someVector.erase(it);

 7     }

 8     else

 9     {

10         ++it;

11     }

12 }

VS的STL带有很多特性,也有BUG。比如下面:

B.我的代码中没有任何关于iterator的使用,只是作为动态数组使用,当vector.clear是报该错误。

被怀疑是VS的BUG。

使用下面的代码则没问题:

1 while(!vec.empty() )

2 {

3   vec.pop_back();

4 };

注:使用empty()来判断为空的效率比使用size高。

C.返回vecotr类型时,一般需要引用符&和const修饰。

常见错误代码:

 1 // testVecotr.cpp : 定义控制台应用程序的入口点。

 2 //

 3 

 4 #include "stdafx.h"

 5 #include <vector>

 6 class foo{

 7 public:

 8 

 9     const std::vector<int> getVec(){return myVec;} //other stuff omitted

10 

11 private:

12     std::vector<int> myVec;

13 

14 };

15 int _tmain(int argc, _TCHAR* argv[])

16 {

17     foo myFoo;

18     std::vector<int>::const_iterator i = myFoo.getVec().begin();

19     while( i != myFoo.getVec().end())

20     {

21         //do stuff

22         ++i;

23     }

24     return 0;

25 }

上述代码在22行会出现vector iterator incompatible的错误。

原因是getVec返回的是一个copy. So the iterators are incompatible.

修改方法是:

const std::vector<int> & getVec(){return myVec;} 

另外的解决方法:当你确实想得到copy时,可以用下面的方法得到iterator.

1 const std::vector<int> myCopy = myFoo.getVec();

2 std::vector<int>::const_iterator i = myCopy.begin();

3 while(i != myCopy.end())

4 {

5   //do stuff

6   ++i;

7 }

 


 

2.临时对象的问题

 返回临时对象的引用或指针是c++中常犯的错误,而返回临时对象是会返回一份临时对象的拷贝。

比如以下代码:getVec返回的是一份vector的拷贝,代码是完全没有问题的。但如果返回的是std::vector<int> &则会出错。

 1 #include<iostream>

 2 #include<vector>

 3 std::vector<int> getVec()

 4 {

 5     std::vector<int> ivec(3,1);

 6     return ivec;

 7 }

 8 int main(void)

 9 {

10     std::vector<int> vecTest=getVec();

11     std::cout<<vecTest.size()<<std::endl;

12     return 0;

13 }

有一篇文章分析了参数临时对象、类型转换和返回对象等三种临时对象的情况。

http://blog.csdn.net/microzone/article/details/6740475


 

3.当前目录的表示方法

  当前目录的表示方法为:..\\input.txt

EnergyAverage("..\\Data\\b_0_core_1.txt");  

 


 

4.C++将string字符串转化为整数等

  首先用string类型的c_str方法转化为const char*,然后用atoi。

  在此也要注意string的其他不常用方法:

    string::assign()

    string::data()

    string::cory()

 


 

5.Segmentation fault in Linux

  SIGSEGV在很多时候是由于指针越界引起的,但并不是所有的指针越界都会引发SIGSEGV。一个越界的指针,如果不解引用它,是不会引起SIGSEGV的。

  链接:http://www.cnblogs.com/no7dw/archive/2013/02/20/2918372.html

     http://www.cnblogs.com/justacoder/archive/2010/04/14/segmentation_fault.html


 

6. 注意区别 strlen和sizeof的区别

  sizeof(...)是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。

  它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。

  strlen(...)是函数,要在运行时才能计算。参数必须是字符型指针(char*)。当数组名作为参数传入时,实际上数组就退化成指针了。
     它的功能是:返回字符串的长度。该字符串可能是自己定义的,也可能是内存中随机的,该函数实际完成的功能是从代表该字符串的第一个地址开始遍历,直到遇到结束符NULL。返回的长度大小不包括NULL。

    eg1、char arr[10] = "What?";

              int len_one = strlen(arr);

              int len_two = sizeof(arr);

              cout << len_one << " and " << len_two << endl;

    输出结果为:5 and 10

    点评:sizeof返回定义arr数组时,编译器为其分配的数组空间大小,不关心里面存了多少数据。strlen只关心存储的数据内容,不关心空间的大小和类型。



    eg2、char * parr = new char[10];

              int len_one = strlen(parr);

              int len_two = sizeof(parr);

              int len_three = sizeof(*parr);

              cout << len_one << " and " << len_two << " and " << len_three << endl;

    输出结果:23 and 4 and 1

  详解:http://3961409.blog.51cto.com/3951409/766017


 7. new创建类对象与不new区别(http://blog.163.com/zhuandi_h/blog/static/18027028820129169538815/)

    • new创建类对象需要指针接收,一处初始化,多处使用
    • new创建类对象使用完需delete销毁
    • new创建对象直接使用堆空间,而局部不用new定义类对象则使用栈空间
    • new对象指针用途广泛,比如作为函数返回值、函数参数等
    • 频繁调用场合并不适合new,就像new申请和释放内存一样

你可能感兴趣的:(学习笔记)