MyMSDN

MyMSDN记录开发新知道

C++ notes (3)

21、vector的动态增长优于预先分配内存。

使用vector的时候最好动态地添加元素。它不同于C和Java或其他语言的数据类型,为了达到连续性,更有效的方法是先初始化一个空vector对象,然后再动态添加元素,而不是预先分配内存。

22、vector值初始化

内置->0

有默认构造->调用默认构造

无默认构造,有其他构造->程序员手动提供初始值

无默认构造,也无其他构造->标准库产生一个带初值的对象

23、数组下标的类型

C++中,数组下标的正确类型是size_t而不是int,size_t是一个与机器相关的unsigned类型。

24、在声明指针的时候,可以用空格将符号*与其后的标识符分隔开来,string *ps与string* ps都是可以的,但后者容易产生误解,如:

string* ps1,ps2;     //ps1是指针,而ps2是一个string对象

也就是说,人们可能误把string和string*当作两个类型,或者说string*被当作一种新类型来看待,但这是错的

25、一个有效的指针必然是以下三种状态之一:

  1. 保存特定的对象的地址;
  2. 指向某个对象后面的另一对象;
  3. 或者是0值。表明它不指向任何对象。

其中int *pi=0;与int *pi;是不同的。前者是初始化指针指向0地址的对象(即为NULL)(pi initialized to address to no object),后者却是未初始化的(ok, but dangerous, pi is uninitialized)。

编译器可以检测出0值的指针,程序可判断该指针并未指向一个对象,而未初始化的指针的使用标准并未定义,对大多数编译器来说,如果使用未初始化的指针会将指针中存放的不确定值视为地址,然后操纵该内存地址中存放的位内容,使用未初始化的指针相当于操纵这个不确定的地址中存储的基础数据,因此对未初始化的指针进行解引用时,通常会导致程序崩溃。

26、void*指针

void*指针只支持几种有限的操作:

  1. 与另一个指针进行比较;
  2. 向函数传递void*指针或从函数返回void*指针;
  3. 给另一个void*指针赋值。

不允许使用void*指针操纵它所指向的对象。

27、指针和引用的比较(P105)

虽然使用引用(reference)和指针都可间接访问另一个值,但它们之间有两个重要区别。第一个区别在于引用总是指向某个对象:定义引用时没有初始化是错误的。第二个重要区别则是赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象(这就是为什么引用必须在定义时初始化的原因)。

28、指针与typedef(P112)

const放在类型前和放在类型后都可以表示同样的意思:

const string s1;
string const s2;

s1和s2均表示常量字符串对象。

但因此就导致了下面的句子可能产生误解:

typedef string *pstring;
const pstring cstr;

容易错把typedef当成文本扩展而产生下面的理解:

const string *cstr; //这并非上面例子的正确意思!(错误)

应该从声明的句子看,也就是说只看const pstring cstr;,在这里pstring是一种指针类型,const修饰的是这个类型,因此正确的理解应该是:

string *const cstr;

而const pstring cstr;其实可以表示为pstring const cstr;,这样的写法则不容易产生误解。从右向左阅读的意思就是:cstr是const pstring类型,即指向string对象的const指针。

29、创建动态数组(注意点见代码注释)

const char *cp1 = "some value";
char *cp2 = "other value";

int *piArray1 = new int[10];    //内置类型没有初始化
int *piArray2 = new int[10]();    //内置类型需要加空圆括号,对数组元素进行初始化
std::string *psArray1 = new std::string[10];    //默认构造函数初始化

std::cout<<"----------"<<std::endl
    <<"*cp1\t\t:"<<*cp1<<std::endl
    <<"*cp2\t\t:"<<*cp2<<std::endl
    <<"*piArray1\t:"<<*piArray1<<std::endl
    <<"*piArray2\t:"<<*piArray2<<std::endl
    <<"*psArray1\t:"<<*psArray1<<std::endl
    <<"----------"<<std::endl;

但是下面的结果却与概念上的不同:

////Visual Studio & MS VC++
//----------                   
//*cp1            :s
//*cp2            :o
//*piArray1       :-842150451
//*piArray2       :0
//*psArray1       :
//----------
////Eclipse&G++
//----------
//*cp1        :s
//*cp2        :o
//*piArray1    :4064608
//*piArray2    :4064560
//*psArray1    :
//----------

看来不同的编译器对此的定义还是有所不同,注意看*piArray2的值,按照说明应该是初始化为0,但这里却仍然表现出与*piArray1一样的值,说明并没有发生初始化。

对于动态分配的数组,其元素只能初始化为元素类型的默认值,而不能像数组变量一样,用初始化列表为数组元素提供各不相同的初值。

30、const对象的动态数组

//P118
//error:uninitialized const array
const int *pciArray1 = new const int[10];
//ok:value-initialized const array
const int *pciArray2 = new const int[10]();
std::cout<<*pciArray1<<std::endl;
std::cout<<*pciArray2<<std::endl;

上面的示例的注释来自书中,但在VC++编译器和G++编译器下却不同,具体表现为:

  • VC++:编译正确,第一句输出随机地址的值,第二句输出初始化的0(其中按照“标准”第一种因为未向const变量初始化,应该无法通过编译,但这里可以)
  • G++:编译错误,第一句的错误信息为“uninitialized const in `new' of `const int'”,但第二句按照标准应该输出0的,这里却输出了随机地址的值。

看来两个编译器对这一问题的看法不太一致。

posted on 2008-12-25 16:13 volnet 阅读(1518) 评论(5)  编辑 收藏 引用 所属分类: C++ Primer 学习笔记

评论

# re: C++ notes (3) 2008-12-25 23:56 夜弓

>>在声明指针的时候,可以用空格将符号*与其后的标识符分隔开来,string *ps与string* ps都是可以的,但后者容易产生误解

虽然一般大家都推荐使用string *p
但我觉得string* p更能表达出p的类型
C++是一门庞大的语言,同样也是一门优美的语言
在绝大部分地方它都是逻辑自洽的
相比而言,string* p就比string *p更优美
如果C++可以像java一样把数组写成
int[] array的话,就更好了

至于这个问题
始终在单行定义变量同样可以解决。  回复  更多评论   

# re: C++ notes (3) 2008-12-26 00:03 volnet

@夜弓
其实不论是哪种类型,自己用习惯了就可以,另外一种,大致了解,以便不会在别人的代码中晕菜即可……
单行的确可以解决这个问题,恩,不过在变量一多的时候,我们可能更经常用多行,事实上,这个也是习惯问题。而且单行可以更好的地注释变量,而多行则通常适用于同一注释的多个变量声明  回复  更多评论   

# re: C++ notes (3) 2008-12-26 09:43 飘飘白云

21、vector的动态增长优于预先分配内存。

使用vector的时候最好动态地添加元素。它不同于C和Java或其他语言的数据类型,为了达到连续性,更有效的方法是先初始化一个空vector对象,然后再动态添加元素,而不是预先分配内存。

-------------------------------------------------------
我记得C++编程思想里面说的给vector预先指定目标容量远比频繁push_back来着有效的多,尤其是元素是对象的时候。 这个也算是预先分配内存的吧,减少内存碎片  回复  更多评论   

# re: C++ notes (3) 2008-12-26 16:00 volnet

@飘飘白云
你说的在理,这句话是Lippman说的,话说他们都是大牛,现在看相信谁的了……
这可能涉及到不同的标准库实现方式,看来这个问题要么应该忽略掉,根据实际需求,可以加的就加,不可以加的就算了。
希望有达人来解释一下  回复  更多评论   

# re: C++ notes (3) 2008-12-27 10:28 夜弓

@volnet
你说的在理
第一是自己习惯
第二是公司的code style接受
@飘飘白云
看是什么东西吧
有些构造函数开销很大
但是复制构造函数开销不大的(shared_ptr 浅复制)
初始化vector为空就很好
比如说SqlConnection  回复  更多评论   


只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理


特殊功能