51
6.11 6.11 宽宽宽宽宽宽宽 宽宽宽宽宽宽宽 宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽 宽宽 宽宽宽宽宽宽 一。 宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽 宽宽 宽宽宽宽宽宽 一。 wstring_alloc,wstring_d wstring_alloc,wstring_d up up wstring_free wstring_free 宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽宽

6.11 宽位字符串映射

  • Upload
    lydie

  • View
    112

  • Download
    0

Embed Size (px)

DESCRIPTION

6.11 宽位字符串映射. 宽位字符串映射与字符串映射基本一样。主要是由函数 wstring_alloc,wstring_dup 和 wstring_free 来完成内存的分配和释放。. 定点数据类型的映射. C++ 中没有定点数据类型,因此 C++ 对定点数据类型的支持与运算是由一个类和一组重载的运算符函数提供。 namespace CORBA{ // …… class Fixed{ // …… };} 通过这一映射,就可以在 C++ 中使用定点数的数值,并对它们进行计算。. 定点数据类型的映射. 6.12.1 构造函数 - PowerPoint PPT Presentation

Citation preview

Page 1: 6.11  宽位字符串映射

6.11 6.11 宽位字符串映射宽位字符串映射 宽位字符串映射与字符串映射基本一样。主要是由函数宽位字符串映射与字符串映射基本一样。主要是由函数 wstring_wstring_

alloc,wstring_dupalloc,wstring_dup 和和 wstring_freewstring_free 来完成内存的分配和释放。来完成内存的分配和释放。

Page 2: 6.11  宽位字符串映射

定点数据类型的映射定点数据类型的映射 C++C++ 中没有定点数据类型,因此中没有定点数据类型,因此 C++C++ 对对

定点数据类型的支持与运算是由一个类定点数据类型的支持与运算是由一个类和一组重载的运算符函数提供。和一组重载的运算符函数提供。

namespace CORBA{namespace CORBA{ //……//…… class Fixed{class Fixed{ //……};}//……};} 通过这一映射,就可以在通过这一映射,就可以在 C++C++ 中使用中使用

定点数的数值,并对它们进行计算。定点数的数值,并对它们进行计算。

Page 3: 6.11  宽位字符串映射

定点数据类型的映射定点数据类型的映射6.12.1 6.12.1 构造函数构造函数 通过构造函数将完成这一转换:通过构造函数将完成这一转换: Fixed f=999;// fied<3,0>Fixed f=999;// fied<3,0> Fixed f1=1000.0;// fied<4,0>Fixed f1=1000.0;// fied<4,0> Fixed f2=1000.05;// fied<6,2>Fixed f2=1000.05;// fied<6,2> Fixed f3=0.1;// fied<18,17>Fixed f3=0.1;// fied<18,17> Fixed f=1E30;// fied<31,0>Fixed f=1E30;// fied<31,0> Fixed f=1E29+0.89;// fied<31,1>-----------1E29+0.8Fixed f=1E29+0.89;// fied<31,1>-----------1E29+0.8 在初始化时由于二进制数表示上的特殊性,也可能会产生在初始化时由于二进制数表示上的特殊性,也可能会产生

一些变化,例如在许多现实中一些变化,例如在许多现实中 0.10.1 的实际值是的实际值是 0.10000000.100000000000000010000000001 。还可能被截断如。还可能被截断如 1E291E29 ++ 0.890.89 被截断为被截断为 1E1E2929 ++ 0.80.8 。。

Page 4: 6.11  宽位字符串映射

定点数据类型的映射定点数据类型的映射 对超过对超过 3131 个的整数位的数值进行初始化个的整数位的数值进行初始化

会产生一个会产生一个 DATA_CONVERSIONDATA_CONVERSION 异常。异常。 构造字符串类型的构造字符串类型的 FixedFixed 值遵循值遵循 IDLIDL 定定

点数常量的规则,字符串前面的点数常量的规则,字符串前面的 00 和后和后面的面的 00 被忽略掉。“被忽略掉。“ d”d” 或“或“ D”D” 是可是可选的。例如:选的。例如:

Fixed f1=“1.2”; fixed<2,1>Fixed f1=“1.2”; fixed<2,1> Fixed f1=“01.20D”; fixed<2,1>Fixed f1=“01.20D”; fixed<2,1>。。

Page 5: 6.11  宽位字符串映射

6.12.2 6.12.2 存取函数存取函数 fixed_digitsfixed_digits 和和 fixed_scalefixed_scale 成员函数分别返回数成员函数分别返回数

值位数和小数位数的值。例如:值位数和小数位数的值。例如: Fixed f=“3.14D”Fixed f=“3.14D” cout<<f.fixed_digits()<<endl; //cout<<f.fixed_digits()<<endl; // 打印打印 33 cout<<f.fixed_scale()<<endl; //cout<<f.fixed_scale()<<endl; // 打印打印 226.12.3 6.12.3 转换运算符转换运算符 LongLongLongLong 转换运算符将一个转换运算符将一个 FixedFixed 值转换为值转换为 LoLo

ngLongngLong 值。值。 LongDoubleLongDouble 转换运算符将一个转换运算符将一个 FixedFixed 值转换为值转换为

LongDoubleLongDouble 值值

Page 6: 6.11  宽位字符串映射

定点数据类型的映射定点数据类型的映射 6.12.4 6.12.4 截断与舍入截断与舍入 truncatetruncate 成员函数返回一个包括指定的数值位数与小数位数的新成员函数返回一个包括指定的数值位数与小数位数的新

的的 FixedFixed 值,并且在需要时,将小数位数进行截断:例如:值,并且在需要时,将小数位数进行截断:例如: Fixed f=“0.99”;Fixed f=“0.99”; cout<<f.truncate(0)<<endl; //cout<<f.truncate(0)<<endl; // 打印打印 00 cout<<f.truncate(1)<<endl; //cout<<f.truncate(1)<<endl; // 打印打印 0.90.9 cout<<f.truncate(2)<<endl; //cout<<f.truncate(2)<<endl; // 打印打印 0.990.99 roundround 成员函数返回一个包含指定的数值位数与小数的新的成员函数返回一个包含指定的数值位数与小数的新的 FixedFixed

值,并舍入为指定的小数位数:值,并舍入为指定的小数位数: Fixed r; Fixed f1=“0.4”; Fixed f2=“0.45”; Fixed f3=“-0.Fixed r; Fixed f1=“0.4”; Fixed f2=“0.45”; Fixed f3=“-0.

445”; 445”; r=f1.round(0); //0 r=f1.round(1); //0.4 r=f2.round(0);//0 r=f1.r=f1.round(0); //0 r=f1.round(1); //0.4 r=f2.round(0);//0 r=f1.

round(1);//0.5 r=f3.round(1);//-0.4 r=f1.round(0);//-0.45round(1);//0.5 r=f3.round(1);//-0.4 r=f1.round(0);//-0.45

Page 7: 6.11  宽位字符串映射

6.13 6.13 结构的映射结构的映射 6.13.1 6.13.1 定长度结构的映射定长度结构的映射 IDLIDL 结构使用相对应的成员映射到结构使用相对应的成员映射到 C++C++ 结构。例如:结构。例如: struct Details{struct Details{ double weight;double weight; unsigned long count;};unsigned long count;}; 映射为:映射为: class Details_var;class Details_var; struct Details{struct Details{ CORBA::double weight;CORBA::double weight; CORBA::unsigned long count;CORBA::unsigned long count; typedef Details_var _var_type;typedef Details_var _var_type; //// 成员函数……成员函数…… };};

Page 8: 6.11  宽位字符串映射

结构的映射结构的映射 可以在代码中使用生成的结构,和使用可以在代码中使用生成的结构,和使用 C++C++ 中的结构一样。例如:中的结构一样。例如: Details d;Details d; d.weight=9.5;d.weight=9.5; d.count=12;d.count=12; C++C++ 允许静态初始化聚集。允许静态初始化聚集。 聚集:一个一个类、结构或数组中没有用户说明的构造函数、基类、聚集:一个一个类、结构或数组中没有用户说明的构造函数、基类、

虚拟函数或私有函数和保护的非静态数据成员,那么这个类、结虚拟函数或私有函数和保护的非静态数据成员,那么这个类、结构或数组都是一个聚集。上述的结构就是一个聚集,因此可以如构或数组都是一个聚集。上述的结构就是一个聚集,因此可以如下初始化:下初始化:

Details d={9.5,12}; Details d={9.5,12};

Page 9: 6.11  宽位字符串映射

6.13.2 6.13.2 变长度结构的映射:变长度结构的映射: 对于变长度的结构,对于变长度的结构, C++C++ 映射就必须解决内存管理的问题。映射就必须解决内存管理的问题。

例如:例如: struct F{struct F{ double num;double num; string al;};string al;}; 映射如下:映射如下: class F_var;class F_var; struct F{struct F{ CORBA::Double num;CORBA::Double num; CORBA::String_mgr al;CORBA::String_mgr al; typedef F_var var_type;typedef F_var var_type; //// 成员函数…… 成员函数…… };};

Page 10: 6.11  宽位字符串映射

结构的映射结构的映射 在此在此 IDLIDL 字符串被映射为一个字符串被映射为一个 String_mgrString_mgr 类类

型,而不是型,而不是 String_varString_var 或或 char *char * 类型。类型。 StriString_mgrng_mgr 类似于类似于 String_var,String_var, 其区别就是其区别就是 StrinString_mgrg_mgr 类中缺省的构造函数将字符串初始化为类中缺省的构造函数将字符串初始化为空字符串,而不是初始化为空指针。空字符串,而不是初始化为空指针。

将篏套的类型初始化为空字符串很有用,因为将篏套的类型初始化为空字符串很有用,因为这就意味着,不需要在将用户自定义类型传递这就意味着,不需要在将用户自定义类型传递给一个给一个 IDLIDL 接口之前,对它内部的所有字符串接口之前,对它内部的所有字符串成员显示进行初始化。成员显示进行初始化。 (( 因为将一个空指针传因为将一个空指针传递给一个递给一个 IDLIDL 接口是非法的。接口是非法的。 )) 。不要在应用。不要在应用程序中将程序中将 String_mgrString_mgr 作为一个类型来使用。作为一个类型来使用。这样的话,代码就不可移植。要用这样的话,代码就不可移植。要用 String_varString_var 。。

除了将字符串初始化为空字符串之外,除了将字符串初始化为空字符串之外, String_String_mgrmgr 与与 String_varString_var 一样,用于内存的自动管一样,用于内存的自动管理,可以相互赋值。理,可以相互赋值。

Page 11: 6.11  宽位字符串映射

结构的映射结构的映射如果一个结构包含一个变长数据类型,结构会管理这一变长类型的如果一个结构包含一个变长数据类型,结构会管理这一变长类型的

内存。因此只需要考虑最外部的内存的内存管理,例如:内存。因此只需要考虑最外部的内存的内存管理,例如: {{ F c;F c; c.num=1.0/3.0;c.num=1.0/3.0; c.al=CORBA::string_dup(“one”);c.al=CORBA::string_dup(“one”); } //} // 没有内存泄漏没有内存泄漏 以上定义了一个局部变量以上定义了一个局部变量 cc ,同时结构中的构造函数对结构中的成,同时结构中的构造函数对结构中的成

员进行初始化。对员进行初始化。对 numnum 成员,构造函数没有做什么。然而,成员,构造函数没有做什么。然而, alal成员是一个篏套字符串,因此构造函数将它初始化为一个空字符成员是一个篏套字符串,因此构造函数将它初始化为一个空字符串。串。

为了给为了给 alal 赋值,必须要分配内存,赋值,必须要分配内存, alal 再次负责这一内存的释放再次负责这一内存的释放(( 赋值会对赋值会对 alal 调用调用 operator=(char *))operator=(char *)) 。 。

Page 12: 6.11  宽位字符串映射

结构的映射结构的映射 当当 cc 离开作用域后,它的缺省析构函数会释放离开作用域后,它的缺省析构函数会释放

所有成员的内存,并且调用所有成员的内存,并且调用 alal 的析构函数,而的析构函数,而alal 的析构函数则会调用的析构函数则会调用 CORBA::string_freeCORBA::string_free 。。这就意味着,当这就意味着,当 cc 离开作用域时不会由内存的离开作用域时不会由内存的泄漏。泄漏。

不能对不能对 cc 进行静态初始化。进行静态初始化。6.13.3 6.13.3 结构的内存管理结构的内存管理 可以将结构与程序中的其它变量进行同样的处可以将结构与程序中的其它变量进行同样的处

理。程序会自己完成大部分的内存管理工作,理。程序会自己完成大部分的内存管理工作,这样就可以自由地将结构和结构成员赋给其它这样就可以自由地将结构和结构成员赋给其它地结构和结构成员。 地结构和结构成员。

Page 13: 6.11  宽位字符串映射

结构的映射结构的映射{ { struct F c1;struct F c2; struct F c3;struct F c1;struct F c2; struct F c3; c1.num=.5;c1.al=CORBA::string_dup(“one”);c1.num=.5;c1.al=CORBA::string_dup(“one”); c2.num=.25;c1.al=CORBA::string_dup(“two”);c2.num=.25;c1.al=CORBA::string_dup(“two”); c3.num=.125;c1.al=CORBA::string_dup(“threc3.num=.125;c1.al=CORBA::string_dup(“thre

e”);e”); c2=c1; //c2=c1; // 深层次赋值深层次赋值C3.al=c1.al; //C3.al=c1.al; // 深层次赋值深层次赋值C3.num=1.0C3.num=1.0C3.al[3]=‘\0’; //C3.al[3]=‘\0’; // 不会影响不会影响 c1c1 和和 c2c2C1.al[0]=‘O’; //C1.al[0]=‘O’; // 不会影响不会影响 c2c2 和和 c3c3C1.al[4]=‘H’; //C1.al[4]=‘H’; // 不会影响不会影响 c2c2 和和 c3c3}//}// 全部释放全部释放

Page 14: 6.11  宽位字符串映射

在结构中,结构及其成员赋值进行的是多层次地拷在结构中,结构及其成员赋值进行的是多层次地拷贝。而且,当结构删除后,由三个字符串所占据贝。而且,当结构删除后,由三个字符串所占据地内存由相应地地内存由相应地 String_mgrString_mgr 析构函数进行自动析构函数进行自动释放。释放。

如果要处理动态分配的结构的话,可以使用如果要处理动态分配的结构的话,可以使用 newnew 和和delete:delete:

F * fp=new F;F * fp=new F; fp->num=335.0/113; fp->al=CORBA::string_dfp->num=335.0/113; fp->al=CORBA::string_d

up(“four”);up(“four”); delete fp;delete fp; 这里不需要调用用于内存分配与释放的辅助函数。这里不需要调用用于内存分配与释放的辅助函数。

Page 15: 6.11  宽位字符串映射

结构的映射结构的映射 6.13.4 6.13.4 包含结构成员的结构包含结构成员的结构 对于结构成员本身就是结构的情况,不需要使用特殊的映射规则,对于结构成员本身就是结构的情况,不需要使用特殊的映射规则,

只不过在调用时需要再加上取成员运算符只不过在调用时需要再加上取成员运算符 (.)(.) 。例如:。例如: c1.result.num;c1.result.num; 其中其中 resultresult 是一个结构变量。是一个结构变量。

Page 16: 6.11  宽位字符串映射

6.14 6.14 序列的映射序列的映射 6.14.1 6.14.1 无界序列的映射无界序列的映射 IDLIDL 序列可以映射成类似于向量的序列可以映射成类似于向量的 C++C++ 类,而向量中的元素数目类,而向量中的元素数目

是可变的。每一个是可变的。每一个 IDLIDL 序列都可以映射成一个单独的序列都可以映射成一个单独的 C++C++ 类。类。例如:例如:

typedef sequence<string> StrSeq;typedef sequence<string> StrSeq; 映射如下:映射如下: class StrSeq_var;class StrSeq_var; class StrSeq {class StrSeq { public:public: …… …… };};

Page 17: 6.11  宽位字符串映射

对其解释如下:对其解释如下:1. StrSeq()1. StrSeq()其函数是缺省构造函数。这个函数将创建一个空序列。调用其函数是缺省构造函数。这个函数将创建一个空序列。调用

一个缺省构造的序列的一个缺省构造的序列的 lengthlength 存取函数将返回数值存取函数将返回数值 00 。 。 2. StrSeq(const StrSeq &)2. StrSeq(const StrSeq &) StrSeq & optertor=(const StrSeq &)StrSeq & optertor=(const StrSeq &) 此为拷贝构造函数和赋值运算符。它们都进行多层次的拷此为拷贝构造函数和赋值运算符。它们都进行多层次的拷

贝。赋值运算符再创建源序列的拷贝之前先撤消目标序列。贝。赋值运算符再创建源序列的拷贝之前先撤消目标序列。如果序列中的元素是变长的,那么这些元素就用它们的拷如果序列中的元素是变长的,那么这些元素就用它们的拷贝构造函数进行多层次的拷贝。目标序列的内部最大值设贝构造函数进行多层次的拷贝。目标序列的内部最大值设为源序列的内部最大值。为源序列的内部最大值。

3. ~StrSeq()3. ~StrSeq() 析构函数用来撤消一个序列。如果序列中包含变长的元素,析构函数用来撤消一个序列。如果序列中包含变长的元素,

那么这些元素的动态内存也将被释放。那么这些元素的动态内存也将被释放。

Page 18: 6.11  宽位字符串映射

序列的映射序列的映射4. CORBA::Ulong length() const4. CORBA::Ulong length() const lengthlength 存取函数只是返回序列中当前的元存取函数只是返回序列中当前的元素的数目。素的数目。

5. Void length(CORBA::Ulong newlen)5. Void length(CORBA::Ulong newlen) 此函数为长度修改函数,可以修改序列的此函数为长度修改函数,可以修改序列的

长度。长度。 增加序列长度会创建增加序列长度会创建 newlennewlen-- lengthlength 个个

新的元素。增加到尾部。由缺省的构造函新的元素。增加到尾部。由缺省的构造函数来完成对增加元素的初始化。数来完成对增加元素的初始化。 (( 如果添如果添加的元素是字符串或包含字符串的复杂类加的元素是字符串或包含字符串的复杂类型,那么字符串被初始化为空字符串。型,那么字符串被初始化为空字符串。 ))

Page 19: 6.11  宽位字符串映射

序列的映射序列的映射 序列长度的减小可以在序列尾部撤消序列长度的减小可以在序列尾部撤消 length()-newlenlength()-newlen 个元素而个元素而

截断序列。如果通过减小长度的方法截断一个序列,那么被截掉截断序列。如果通过减小长度的方法截断一个序列,那么被截掉的元素会永久地被撤消掉。的元素会永久地被撤消掉。

6. CORBA::String_mgr & operator[](CORBA::Ulong idx)6. CORBA::String_mgr & operator[](CORBA::Ulong idx) const char* operator[](CORBA::Ulong idx) constconst char* operator[](CORBA::Ulong idx) const 下标运算符提供了对元素地访问功能。下标运算符提供了对元素地访问功能。 序列地下标由序列地下标由 00 到到 length()-1length()-1 。如果下标超出序列地长度地话,。如果下标超出序列地长度地话,

会产生不可预料地结果。会产生不可预料地结果。

Page 20: 6.11  宽位字符串映射

序列的映射序列的映射 序列地简单使用序列地简单使用 一旦序列离开作用域,它就会调用其元素析构函数释放所有元素。一旦序列离开作用域,它就会调用其元素析构函数释放所有元素。 为了管理由堆分配的序列,可以使用为了管理由堆分配的序列,可以使用 newnew 和和 deletedelete ;; StrSeq * sq=new StrSeq;StrSeq * sq=new StrSeq; sq->length(4);sq->length(4); for(……)for(……) (*sq)[i]=values[i];(*sq)[i]=values[i]; //……//…… delete sq;delete sq; 在此使用的是在此使用的是 (*sq)[i]=values[i](*sq)[i]=values[i] ,这将间接引用这个指针,间接,这将间接引用这个指针,间接引用这个指针是必要的,因为需要用于下标运算符的引用这个指针是必要的,因为需要用于下标运算符的 StrSeqStrSeq 类类型的表达式。如果用型的表达式。如果用 sq[i]=values[i]sq[i]=values[i] 就会产生错误,编译器会假就会产生错误,编译器会假定在处理序列的数组,并且将定在处理序列的数组,并且将 const char *const char * 赋值给序列的第个赋值给序列的第个 ii元素,这样会造成编译时的错误。元素,这样会造成编译时的错误。

Page 21: 6.11  宽位字符串映射

序列的映射序列的映射 控制序列的最大值控制序列的最大值 当构造一个序列变量时,可以通过最大值构造函数当构造一个序列变量时,可以通过最大值构造函数

提供一个序列中元素的最大数目:提供一个序列中元素的最大数目: StrSeq myseq(10); //StrSeq myseq(10); // 打算输入打算输入 1010 个元素到序列中个元素到序列中 myseq.length(20); //myseq.length(20); // 最大值没有限制序列的长度最大值没有限制序列的长度 for(CORBA::ULOng i=0; i<myseq.length();i++)for(CORBA::ULOng i=0; i<myseq.length();i++) //// 初始化初始化 即使代码中使用的最大元素数目是即使代码中使用的最大元素数目是 1010 个,序列中个,序列中

也会添加也会添加 2020 个元素。这样做完全没问题,序列中会个元素。这样做完全没问题,序列中会添加一些附加的元素以增加其长度。添加一些附加的元素以增加其长度。

Page 22: 6.11  宽位字符串映射

提供序列的最大值主要与内部管理缓冲区有关。如提供序列的最大值主要与内部管理缓冲区有关。如果使用最大值构造函数,序列会把一个内部的最果使用最大值构造函数,序列会把一个内部的最大值设为至少与所给的指一样大的值。此外,序大值设为至少与所给的指一样大的值。此外,序列保证了在当前长度没有超过最大值时,不会再列保证了在当前长度没有超过最大值时,不会再次为元素分配内存。次为元素分配内存。

还有可以提供高效。如果序列能够知道我们所想还有可以提供高效。如果序列能够知道我们所想要的元素数目,那么它就可以更加有效的分配内要的元素数目,那么它就可以更加有效的分配内存。减少了内存分配函数的 调用次数,并且减少存。减少了内存分配函数的 调用次数,并且减少了在增加序列长度时拷贝元素的次数。了在增加序列长度时拷贝元素的次数。

Page 23: 6.11  宽位字符串映射

序列的映射序列的映射 注意:注意: (1) (1) 映射并不是每次调用最大值构造函数映射并不是每次调用最大值构造函数

时,它会预先分配内存。相反,直到第时,它会预先分配内存。相反,直到第一个元素创建后才会分配内存。一个元素创建后才会分配内存。

(2) (2) 映射并不是保证最大值构造函数分配映射并不是保证最大值构造函数分配的正好是序列所需的内存,它可能分配的正好是序列所需的内存,它可能分配的更多一些。的更多一些。

(3) (3) 映射并不保证最大值构造函数一次就映射并不保证最大值构造函数一次就能序列元素所需的内存,它可能会在几能序列元素所需的内存,它可能会在几个不连续的缓冲区中分配序列元素的内个不连续的缓冲区中分配序列元素的内存。存。

Page 24: 6.11  宽位字符串映射

(4) (4) 映射并不保证序列元素占据一块连续的内存区域。为了映射并不保证序列元素占据一块连续的内存区域。为了避免再次分配元素,序列在扩展时可能会添加一些新的不避免再次分配元素,序列在扩展时可能会添加一些新的不连续的缓冲空间。连续的缓冲空间。

(5) (5) 映射并不保证增加序列的长度会立即缺省构造新创建的映射并不保证增加序列的长度会立即缺省构造新创建的元素,映射的实现会直到赋给一个新的元素后才进行元素元素,映射的实现会直到赋给一个新的元素后才进行元素的构造,在这个时候才会用拷贝构造函数创建这个元素。的构造,在这个时候才会用拷贝构造函数创建这个元素。

如果知道元素的最大数目,就可以使用最大值构造函数来如果知道元素的最大数目,就可以使用最大值构造函数来获得更好的运行时性能。负责不要用这个函数。获得更好的运行时性能。负责不要用这个函数。

不要使用指向序列元素的指针。如果要只用的话,那么就不要使用指向序列元素的指针。如果要只用的话,那么就必须非常注意再次分配内存问题。因为再次定位将会使指必须非常注意再次分配内存问题。因为再次定位将会使指针失效。针失效。

Page 25: 6.11  宽位字符串映射

序列的映射序列的映射 6.14.2 6.14.2 有界序列的映射有界序列的映射 除了序列的最大值由所生成的类提供之外,有界序列的映射与无除了序列的最大值由所生成的类提供之外,有界序列的映射与无界序列的映射一样。界序列的映射一样。

有界序列与无界序列的区别只是在于,有界序列中没有最大值构造有界序列与无界序列的区别只是在于,有界序列中没有最大值构造函数,数据构造函数不会接收一个最大值参数。函数,数据构造函数不会接收一个最大值参数。

有界序列的长度超出最大值的话,那么就会出现不可预料的结构,有界序列的长度超出最大值的话,那么就会出现不可预料的结构,往往使核心存储。往往使核心存储。

6.14.3 6.14.3 序列使用中的一些限制序列使用中的一些限制 1. 1. 元素的插入与删除元素的插入与删除 序列映射中只是在序列的尾部改变序列的长度。如果想要将一个元序列映射中只是在序列的尾部改变序列的长度。如果想要将一个元素插入到序列中,那么就必须把元素拷贝到插入点的右侧方来把素插入到序列中,那么就必须把元素拷贝到插入点的右侧方来把序列分开。下面的附注函数预先把元素插入到序列中一个指定的序列分开。下面的附注函数预先把元素插入到序列中一个指定的位置。如果指定位置的下标与序列的长度相同,则会插入在序列位置。如果指定位置的下标与序列的长度相同,则会插入在序列的尾部添加这一元素。函数中只能使用的尾部添加这一元素。函数中只能使用 00 到到 length()length()范围内的下范围内的下标值。标值。

Page 26: 6.11  宽位字符串映射

序列的映射序列的映射void pre_insert(……)void pre_insert(……) { { seq.length(seq.length()+1);seq.length(seq.length()+1); for(CORBA::Ulong I=seq.length()-1;I>idx;I--)for(CORBA::Ulong I=seq.length()-1;I>idx;I--) seq[I]=seq[I-1];seq[I]=seq[I-1]; seq[idx]=elmt;//idxseq[idx]=elmt;//idx 为此元素要插入的位置,为此元素要插入的位置, elmtelmt 的值的值 }} 这段代码在原序列中增加一个元素,然后从序列的插入点到尾部一这段代码在原序列中增加一个元素,然后从序列的插入点到尾部一

个一个拷贝元素,从而将序列分开,最后给新的元素赋值。个一个拷贝元素,从而将序列分开,最后给新的元素赋值。删除元素可以用同样的代码,需要在删除点的左侧把序列连接起来:删除元素可以用同样的代码,需要在删除点的左侧把序列连接起来:void remove(……)void remove(……){{ for(CORBA::Ulong I=idx;I<seq.length()-1;I++)for(CORBA::Ulong I=idx;I<seq.length()-1;I++) seq[I]=seq[I+1];seq[I]=seq[I+1]; seq.length(seq.length()-1);seq.length(seq.length()-1);} }

Page 27: 6.11  宽位字符串映射

序列的映射序列的映射 如果经常进行插入与删除,尤其是对于具有复杂类型元素的长序如果经常进行插入与删除,尤其是对于具有复杂类型元素的长序列,这一性能就变得不太理想。在这种情况下,最好选择更为适列,这一性能就变得不太理想。在这种情况下,最好选择更为适合的数据类型。合的数据类型。

6.14.4 6.14.4 序列的使用规则序列的使用规则 下面是安全使用序列的一些规则:下面是安全使用序列的一些规则: (1) (1) 不要去考虑什么时候会调用构造函数和析构函数。序列映射的不要去考虑什么时候会调用构造函数和析构函数。序列映射的

实现完全可能因为效率上的原因而延迟元素的构造或释放。只能实现完全可能因为效率上的原因而延迟元素的构造或释放。只能假定元素在第一次赋值时由拷贝生成,在第一次访问时进行缺省假定元素在第一次赋值时由拷贝生成,在第一次访问时进行缺省的构造,在序列的长度减小时或离开作用域后撤消。的构造,在序列的长度减小时或离开作用域后撤消。

(2) (2) 如果如果 releaserelease 标志为标志为 falsefalse ,就不要将序列传递给一个函数,,就不要将序列传递给一个函数,以对序列进行修改。如果序列没有对缓冲去的所用权的话,被调以对序列进行修改。如果序列没有对缓冲去的所用权的话,被调用的函数在改变序列元素时可能造成内存泄漏。用的函数在改变序列元素时可能造成内存泄漏。

(3) (3) 避免使用复杂类型的数据构造函数,对于复杂类型,数据构造避免使用复杂类型的数据构造函数,对于复杂类型,数据构造函数并没有任何优势,只会使源代码更为复杂。函数并没有任何优势,只会使源代码更为复杂。

(4) (4) 记住,序列长度超出当前最大值的话会使元素在内存中再次定记住,序列长度超出当前最大值的话会使元素在内存中再次定位。位。

Page 28: 6.11  宽位字符串映射

序列的映射序列的映射(5) (5) 不要将序列的下标值超出序列的当前长度不要将序列的下标值超出序列的当前长度(6) (6) 不要使有界序列的长度增长到超出它的边界不要使有界序列的长度增长到超出它的边界(7) (7) 不要使用数据构造函数或缓冲区操作函数,除非确实需要。对缓冲不要使用数据构造函数或缓冲区操作函数,除非确实需要。对缓冲

区进行直接操作容易造成潜在的内存管理的错误。区进行直接操作容易造成潜在的内存管理的错误。 (( 因为数据构造函因为数据构造函数的问题很多,尽量不要使用此函数,因此没有介绍。数的问题很多,尽量不要使用此函数,因此没有介绍。 ))

Page 29: 6.11  宽位字符串映射

6.15 6.15 数组的映射数组的映射 IDLIDL 数组可以映射成具有对应元素类型数组可以映射成具有对应元素类型

的的 C++C++ 数组。字符串元素被映射成数组。字符串元素被映射成 StriString_mgrng_mgr 。这里的关键之处是字符串元。这里的关键之处是字符串元素初始化为空字符串,否则的话,字符素初始化为空字符串,否则的话,字符串元素类似于串元素类似于 String_var(String_var( 也就是说,也就是说,需要考虑内存管理需要考虑内存管理 )) 。。

内存分配函数返回一个空指针,以表示内存分配函数返回一个空指针,以表示函数调用失败,并不发送函数调用失败,并不发送 CORBACORBA 或或 C+C+++ 异常。异常。

Page 30: 6.11  宽位字符串映射

内存分配函数使用代码中生成的数组的切片类型。一个数内存分配函数使用代码中生成的数组的切片类型。一个数组的切片是第一维元素的类型组的切片是第一维元素的类型 (( 或者,对于二维数组就是或者,对于二维数组就是行的类型行的类型 )) 。在。在 C++C++ 中,数组的表达式可以转换成指向第中,数组的表达式可以转换成指向第一个元素的指针,而切片类型使该类型的指针的说明变得一个元素的指针,而切片类型使该类型的指针的说明变得简单。对于一个数组类型简单。对于一个数组类型 T,T, 指向第一个元素的指针可以指向第一个元素的指针可以说明为说明为 T_slice *T_slice * 。因为。因为 IDLIDL 数组映射为数组映射为 C++C++ 的实际数组,的实际数组,所以可以通过指针算法来遍历数组的元素。所以可以通过指针算法来遍历数组的元素。

StrArray_copyStrArray_copy 函数用于对数组的内容进行深层次拷贝,函数用于对数组的内容进行深层次拷贝,使用时既不需要对源数组进行动态分配,也不需要对目标使用时既不需要对源数组进行动态分配,也不需要对目标数组进行动态分配。这一函数可以有效地实现数组地赋值。数组进行动态分配。这一函数可以有效地实现数组地赋值。(( 因为因为 IDLIDL 数组被映射为数组被映射为 C++C++ 数组,而数组,而 C++C++ 数组并不支数组并不支持数组地赋值,所以映射不能提供用于数组赋值地重载运持数组地赋值,所以映射不能提供用于数组赋值地重载运算符。算符。 ) )

Page 31: 6.11  宽位字符串映射

6.16 6.16 联合的映射联合的映射 IDLIDL 联合不能被映射为联合不能被映射为 C++C++联合,变长度地联合成员被映射成类,联合,变长度地联合成员被映射成类,但是但是 C++C++ 不允许联合中包含带有特殊构造函数地类成员。此外,不允许联合中包含带有特殊构造函数地类成员。此外,C++C++联合不带有判断功能。为了解决这些问题,联合不带有判断功能。为了解决这些问题, IDLIDL 联合被映射联合被映射成成 C++C++ 类。例如:类。例如:

union U switch(char){union U switch(char){ case’L’:case’L’: long long_mem;long long_mem; case’c’:case’c’: case’C’case’C’ char char_mem;char char_mem; default:default: long long_mem;long long_mem; };};对应的对应的 C++C++ 类中还有一个用于存取每个联合成员的成员函数和一个类中还有一个用于存取每个联合成员的成员函数和一个

用于修改每个联合成员的成员函数。此外,还有用于控制鉴别器用于修改每个联合成员的成员函数。此外,还有用于控制鉴别器和解决初始化和赋值问题的成员函数。映射如下:和解决初始化和赋值问题的成员函数。映射如下:

Page 32: 6.11  宽位字符串映射

联合的映射联合的映射Class U_var;Class U_var;Class U{Class U{Public:Public:U(); U(const U &); ~U();U(); U(const U &); ~U();U & operator=(const U &);U & operator=(const U &);CORBA::char _d() const;CORBA::char _d() const;void _d(CORBA::Char);void _d(CORBA::Char);CORBA::Long long_mem() const;CORBA::Long long_mem() const;void long_mem(CORBA::Long); CORBA::char char_mem() covoid long_mem(CORBA::Long); CORBA::char char_mem() co

nst;nst;void char_mem(CORBA::Char); const char * string_mem() covoid char_mem(CORBA::Char); const char * string_mem() co

nst;nst;void string_mem(char*); void string_mem(const char *);void string_mem(char*); void string_mem(const char *);void string_mem(const CORBA::String_var &);void string_mem(const CORBA::String_var &);Typedef U-var _var_type;};Typedef U-var _var_type;};对于其它对于其它 IDLIDL 类型,可能在类中还会有其它的成员函数。如果有的话,类型,可能在类中还会有其它的成员函数。如果有的话,

这些函数是映射实现的内部函数,可以不用考虑。这些函数是映射实现的内部函数,可以不用考虑。

Page 33: 6.11  宽位字符串映射

联合的映射联合的映射 6.16.1 6.16.1 联合的初始化和赋值联合的初始化和赋值 1. U()1. U() 联合的缺省构造函数不会在应用程序中对类进行初始化,这就是联合的缺省构造函数不会在应用程序中对类进行初始化,这就是

说必须在读取联合的内容之前对联合进行初始化,甚至不允许读说必须在读取联合的内容之前对联合进行初始化,甚至不允许读取一个缺省构造的联合的鉴别器的值。取一个缺省构造的联合的鉴别器的值。

2. U(const U &)2. U(const U &) U & operator=(const U &) U & operator=(const U &) 拷贝函数和赋值运算符进行多层次拷贝,因此如果联合中包含一个拷贝函数和赋值运算符进行多层次拷贝,因此如果联合中包含一个

字符串,那么字符串内容就可以进行正确地拷贝。字符串,那么字符串内容就可以进行正确地拷贝。 3. 3. ~~ U()U() 析构函数用于撤消一个联合。如果联合中包含了一个变长度成员,析构函数用于撤消一个联合。如果联合中包含了一个变长度成员,

那么给成员函数分配地内容就可以正确地释放。撤消一个未初始那么给成员函数分配地内容就可以正确地释放。撤消一个未初始化地缺省构造联合是安全的。化地缺省构造联合是安全的。

Page 34: 6.11  宽位字符串映射

联合的映射联合的映射 6.16.2 6.16.2 联合的成员与鉴别器的访问联合的成员与鉴别器的访问 为了激活一个联合成员或给一个联合成员赋值,可以调用相应的为了激活一个联合成员或给一个联合成员赋值,可以调用相应的修改成员函数。给一个联合成员赋值也可以设置鉴别器的数值,修改成员函数。给一个联合成员赋值也可以设置鉴别器的数值,可以通过调用可以通过调用 _d_d 成员函数读取鉴别器的数值。例如:成员函数读取鉴别器的数值。例如:

U my_u; //U my_u; // 没有初始化没有初始化 my_u.long_mem(99); //my_u.long_mem(99); // 激活激活 long_memlong_mem assert(my_u._d()==‘L’); //assert(my_u._d()==‘L’); // 验证鉴别器验证鉴别器 assert(my_u.long_mem()==99); //assert(my_u.long_mem()==99); // 验证值验证值 以上没有在调用缺省的构造函数后对联合进行初始化。调用以上没有在调用缺省的构造函数后对联合进行初始化。调用 long_long_

memmem 成员的修改成员函数可以对联合进行初始化,因为这样的成员的修改成员函数可以对联合进行初始化,因为这样的话会激活该成员,并设置它的值。话会激活该成员,并设置它的值。

为了改变联合中激活的成员,可以调用另外一个成员的修改函数,为了改变联合中激活的成员,可以调用另外一个成员的修改函数,以给该成员赋值:以给该成员赋值:

my_u.char_mem(‘X’);//my_u.char_mem(‘X’);// 激活和分配给激活和分配给 char_memchar_mem my_u._d(‘C’);//my_u._d(‘C’);// 现在变成了‘现在变成了‘ C’C’

Page 35: 6.11  宽位字符串映射

联合的映射联合的映射 上面的代码首先激活成员上面的代码首先激活成员 char_memchar_mem ,此激活成员可以将鉴别,此激活成员可以将鉴别器设为‘器设为‘ c’c’ 或‘或‘ C’C’ 其中的一个,但是无法知道到底是那一个其中的一个,但是无法知道到底是那一个值。上述代码在激活成员后,将鉴别器的值明确设为‘值。上述代码在激活成员后,将鉴别器的值明确设为‘ C’C’ 。。

如果设置鉴别器的值会激活或失效一个成员的话,那么就不能设如果设置鉴别器的值会激活或失效一个成员的话,那么就不能设置鉴别器的值:置鉴别器的值:

my_u.char_mem(‘X‘); //my_u.char_mem(‘X‘); // 激活和分配激活和分配 char_memchar_mem assert(my_u._d()==‘c’||my_u._d()==‘C’);assert(my_u._d()==‘c’||my_u._d()==‘C’); my_u._d(‘c’); //okmy_u._d(‘c’); //ok my_u._d(‘C’); //okmy_u._d(‘C’); //ok my_u._d(‘X’); //my_u._d(‘X’); // 非法,将激活非法,将激活 string_memstring_mem 只能将鉴别器设为与当前激活的联合成员一致的值只能将鉴别器设为与当前激活的联合成员一致的值 (( 这里合法的这里合法的

值是‘值是‘ c’c’ 和‘和‘ C’)C’) 。。设置联合的缺省成员可以使鉴别器设定未定义的状态。设置联合的缺省成员可以使鉴别器设定未定义的状态。上面的例子还说明。联合内部的字符串成员的作用类似于上面的例子还说明。联合内部的字符串成员的作用类似于 String_vaString_va

rr 。尤其是用于。尤其是用于 string_memstring_mem 成员的修改成员函数是重载的,可成员的修改成员函数是重载的,可以分别用于以分别用于 const char *const char * 、、 char *char * 和和 String_var &String_var & 。通常,。通常, cchar *har *修改函数拥有对字符串的所有权,而修改函数拥有对字符串的所有权,而 const char *const char * 和和 StrinString_varg_var 修改函数进行多层次拷贝。修改函数进行多层次拷贝。

Page 36: 6.11  宽位字符串映射

联合的映射联合的映射 6.16.3 6.16.3 没有没有 defaultdefault 语句的联合语句的联合 下面是一个可以用来模拟可选参数的联合:下面是一个可以用来模拟可选参数的联合: union AgeOpt switch(boolean){union AgeOpt switch(boolean){ case TURE:case TURE: unsigned short age;}unsigned short age;} 这一联合没有这一联合没有 defaultdefault 语句,但是当鉴别器为语句,但是当鉴别器为 FALSEFALSE 时有一隐式时有一隐式

缺省成员。如果联合有一个隐式缺省成员,那么映射将会生成一缺省成员。如果联合有一个隐式缺省成员,那么映射将会生成一个附加的用于相应的个附加的用于相应的 C++C++ 类的类的 _default_default 成员函数。成员函数。

class AgeOpt_var;class AgeOpt_var; class AgeOpt{class AgeOpt{ …… …… void _default();void _default(); typedef AgeOpt_var _var_type;};typedef AgeOpt_var _var_type;}; 映射遵照一些常规的准则,也会添加映射遵照一些常规的准则,也会添加 _default_default 成员函数。成员函数。 _defa_defa

ultult 成员函数可以激活联合的隐式缺省成员,并且相应地设置鉴成员函数可以激活联合的隐式缺省成员,并且相应地设置鉴别器地值:别器地值:

Page 37: 6.11  宽位字符串映射

联合的映射联合的映射 AgeOpt my_age();AgeOpt my_age(); my_age._default(); //my_age._default(); // 设置鉴别器为假设置鉴别器为假在这种情况下,鉴别器的唯一合法的值是在这种情况下,鉴别器的唯一合法的值是 0(0( 表示表示 FALSE)FALSE) 。然而下。然而下

面的语句是非法的:面的语句是非法的:AgeOpt my_age;AgeOpt my_age;my_age._d(0); //my_age._d(0); // 非法非法在此通过设置鉴别器来激活一个联合成员是非法的。在此通过设置鉴别器来激活一个联合成员是非法的。 ((联合中不存联合中不存

在的隐式成员会被当作联合中的一个成员。在的隐式成员会被当作联合中的一个成员。 ))同样,不能通过设置鉴别器的方法把一个已初始化的联合重新设置同样,不能通过设置鉴别器的方法把一个已初始化的联合重新设置

为缺省的成员,必须使用为缺省的成员,必须使用 _default_default 成员函数:成员函数:AgeOpt my_age;AgeOpt my_age;my_age.age(38); //my_age.age(38); // 设置鉴别器为设置鉴别器为 11my_age._d(0); //my_age._d(0); // 非法 非法 my_age._default(); //my_age._default(); // 成功成功

Page 38: 6.11  宽位字符串映射

联合的映射联合的映射 下面是一个有趣的联合:下面是一个有趣的联合: enum HowManyProps{none,some;all};enum HowManyProps{none,some;all}; union SpecifiedProps switch(HowmanyProps){union SpecifiedProps switch(HowmanyProps){ case some:case some: ProperyNameSeq prop_names;};ProperyNameSeq prop_names;}; 联合中允许两个非数值的鉴别器的值:联合中允许两个非数值的鉴别器的值: nonenone 和和 allall 。假设对联合。假设对联合

进行初始化,以将鉴别器的值设置为进行初始化,以将鉴别器的值设置为 nonenone ,这里再次需要使用,这里再次需要使用_default_default 成员函数:成员函数:

SpecifiedProps sp;SpecifiedProps sp; sp._default();//sp._default();// 显式激活默认成员,鉴别器现在是显式激活默认成员,鉴别器现在是 nonenone 或者或者 allall sp._d(none);//sp._d(none);// 固定鉴别器固定鉴别器 必须要调用必须要调用 _default()_default() 。如果不调用。如果不调用 _default_default 的话,就需要设置的话,就需要设置鉴别器来激活隐含的缺省成员,可这是非法的。鉴别器来激活隐含的缺省成员,可这是非法的。

Page 39: 6.11  宽位字符串映射

联合的映射联合的映射 6.14.4 6.14.4 包含复杂成员的联合包含复杂成员的联合 如果联合中包含了一个如果联合中包含了一个 anyany 类型的成员,或者包含了结构、联合、类型的成员,或者包含了结构、联合、

序列或定点数类型的成员,那么生成的类中将包含三个作用于每序列或定点数类型的成员,那么生成的类中将包含三个作用于每个联合成员的成员函数,而不是通常的两个成员函数。个联合成员的成员函数,而不是通常的两个成员函数。

struct Details{struct Details{ double weight;double weight; long count;};long count;};typedef sequence<string> TextSeq;typedef sequence<string> TextSeq;union ShippingInfo switch(long){union ShippingInfo switch(long){case 0:case 0: Details packaging_info;Details packaging_info;default:default: TextSeq other_info;};TextSeq other_info;};其中一个是一个结构,另一个是一个序列。映射如下:其中一个是一个结构,另一个是一个序列。映射如下:

Page 40: 6.11  宽位字符串映射

联合的映射联合的映射class ShippingInfo {class ShippingInfo {publicpublic :: const Details & dl_mem() const;//const Details & dl_mem() const;//获得获得 void dl_mem(const Details &);//void dl_mem(const Details &);//修改修改 Details & dl_mem();//Details & dl_mem();//引用引用 const TextSeq & seq_mem() const;//const TextSeq & seq_mem() const;// 获得获得 void seq_mem(const Details &);//void seq_mem(const Details &);//修改修改 TextSeq & seq_mem();//TextSeq & seq_mem();//引用引用};};对于一些简单的类型,联合中包含了返回成员值的存取函数。对于一些简单的类型,联合中包含了返回成员值的存取函数。 (( 为为

了避免不必要的数据拷贝,作用于复杂类型的存取函数返回常量了避免不必要的数据拷贝,作用于复杂类型的存取函数返回常量引用类型的数值引用类型的数值 )) ,同时,对于简单的类型,每个成员函数都有,同时,对于简单的类型,每个成员函数都有一个进行多层次拷贝的修改函数。一个进行多层次拷贝的修改函数。

引用成员函数返回一个对联合成员的非常量引用,使用这个成员函引用成员函数返回一个对联合成员的非常量引用,使用这个成员函数可以提高效率。对于大的数据类型,通过调用存取函数和修改数可以提高效率。对于大的数据类型,通过调用存取函数和修改函数对函数进行修改的效率很低,因为这两个函数都进行多层次函数对函数进行修改的效率很低,因为这两个函数都进行多层次拷贝。通过引用就可以修改联合成员的值,而不用进行拷贝。拷贝。通过引用就可以修改联合成员的值,而不用进行拷贝。

Page 41: 6.11  宽位字符串映射

联合的映射联合的映射 如果获得一个对联合成员的引用,这个成员必须是当前和如果获得一个对联合成员的引用,这个成员必须是当前和 ÷÷ 激活激活

的。一旦有了一个对联合成员的引用,必须在相应成员处于激活的。一旦有了一个对联合成员的引用,必须在相应成员处于激活状态时才能使用这个成员。状态时才能使用这个成员。

6.16.56.16.5 下面时安全使用联合的一些规则:下面时安全使用联合的一些规则:(1) (1) 不要试图访问一个与鉴别器不一致的联合成员。不要试图访问一个与鉴别器不一致的联合成员。(2) (2) 不要假定联合成员在内存中会重叠。在不要假定联合成员在内存中会重叠。在 CC 和和 C++C++ 中,联合成员中,联合成员

在内存中可以彼此重叠。然而,在在内存中可以彼此重叠。然而,在 IDLIDL 联合的联合的 C++C++ 映射并不提映射并不提供这一功能。供这一功能。

(3) (3) 不要猜测什么时候会调用析构函数。不要猜测什么时候会调用析构函数。 C++C++ 映射并不指明什么时映射并不指明什么时候应该撤消联合的成员。如果激活一个新的成员,那么可能会因候应该撤消联合的成员。如果激活一个新的成员,那么可能会因为效率的原因而推迟调用先前成员的析构函数。为效率的原因而推迟调用先前成员的析构函数。

Page 42: 6.11  宽位字符串映射

6.17 6.17 递归结构和递归联合的映射递归结构和递归联合的映射 考虑下面的递归联合:考虑下面的递归联合: union Link switch(long){union Link switch(long){ case 0:case 0: typeA ta;typeA ta; case 1:case 1: typeB tb;typeB tb; case 2:case 2: sequence<Link> sc;};sequence<Link> sc;};上面的联合中包含一个递归成员上面的联合中包含一个递归成员 scsc 。假设想要激活联合中的。假设想要激活联合中的 scsc 成成

员,使得为一个空序列。激活一个联合成员的唯一方法就是向存员,使得为一个空序列。激活一个联合成员的唯一方法就是向存取器传递该成员的值,然而,取器传递该成员的值,然而, scsc 是一个匿名类型,那么,如何来是一个匿名类型,那么,如何来说明一个这样类型的变量。说明一个这样类型的变量。

C++C++ 映射可以通过在联合类中生成一个附加的类型定义来解决这映射可以通过在联合类中生成一个附加的类型定义来解决这一问题:一问题:

calss Link{calss Link{ public:public: typedef some_internal_identifier_sc_seq;typedef some_internal_identifier_sc_seq; //// 别的成员别的成员 };};

Page 43: 6.11  宽位字符串映射

递归结构和递归联合的映射递归结构和递归联合的映射 生成类中定义了一个生成类中定义了一个 _sc_seq_sc_seq 类型名称来表示匿名类型。总的来类型名称来表示匿名类型。总的来

说,如果联合说,如果联合 uu 中包含了一个匿名类型的中包含了一个匿名类型的 memmem 成员,那么成员,那么 mememm 的类型就是的类型就是 u::_mem_sequ::_mem_seq 。可以使用这个名称来正确地激活。可以使用这个名称来正确地激活联合中地递归成员:联合中地递归成员:

Link::_sc_seq myseq;//myseqLink::_sc_seq myseq;//myseq 是空的是空的 Link mylink;Link mylink; mylink.sc(myseq)//mylink.sc(myseq)//激活激活 scsc这一映射规则也可以用于递归地结构。如果一个结构这一映射规则也可以用于递归地结构。如果一个结构 ss 中包含了一中包含了一

个匿名成员个匿名成员 memmem ,那么,那么 memmem 地类型名就是地类型名就是 s::_mem_seqs::_mem_seq 。。6.18 6.18 类型定义的映射类型定义的映射 IDLIDL 类型定义可以映射为类型定义可以映射为 C++C++ 中对于的类型定义。类型的别名可中对于的类型定义。类型的别名可

以与初始类型一样使用。以与初始类型一样使用。

Page 44: 6.11  宽位字符串映射

6.19 6.19 用户定义类型和用户定义类型和 _var_var 类类 6.19.1 6.19.1 用于结构、联合和序列的用于结构、联合和序列的 _var_var 类类 class T_car{class T_car{ …… …… };};解释如下:解释如下:1. T_var();1. T_var(); 缺省的构造函数将指向当前使用的实例的内部指针初始化为空指缺省的构造函数将指向当前使用的实例的内部指针初始化为空指

针。这样做的结果是在初始化缺省构造的针。这样做的结果是在初始化缺省构造的 _var_var 实例之前,不能实例之前,不能使用它。使用它。

2. T_var(T *)2. T_var(T *) 指针构造函数假定传递的指针指向一个动态分配的实例,并且拥指针构造函数假定传递的指针指向一个动态分配的实例,并且拥

有对指针的所有权。有对指针的所有权。3. T_var(const T_var &)3. T_var(const T_var &) 拷贝构造函数对拷贝构造函数对 T_varT_var 和和 TT 类型的当前使用实例进行多层次拷贝。类型的当前使用实例进行多层次拷贝。4. 4. ~~ T_var()T_var() 析构函数释放由内部指针所指向的实例。析构函数释放由内部指针所指向的实例。

Page 45: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 5. T_var & operator=(T *)5. T_var & operator=(T *) 指针赋值运算符首先释放当前由指针赋值运算符首先释放当前由 T_varT_var拥有的类型拥有的类型 TT 的实例,然后的实例,然后承担由参数所指的实例的所有权。承担由参数所指的实例的所有权。

6. T_var & operator=(const T_var &)6. T_var & operator=(const T_var &) T_varT_var 赋值运算符首先释放当前由赋值运算符首先释放当前由 T_varT_var拥有的类型拥有的类型 TT 的实例,然的实例,然

后对后对 T_varT_var参数和参数和 T_varT_var参数所指向的类型参数所指向的类型 TT 的实例进行多层次的实例进行多层次拷贝。拷贝。

7. T * operator->()7. T * operator->() const T * operator->() constconst T * operator->() const 重载间接运算符是为了可以让运算符用于常量和当前使用类型的非重载间接运算符是为了可以让运算符用于常量和当前使用类型的非

常量实例。运算符返回一个指向当前使用实例的指针。这意味着,常量实例。运算符返回一个指向当前使用实例的指针。这意味着,可以通过可以通过 T_varT_var 来调用基本类型的任何成员函数。来调用基本类型的任何成员函数。

8. operator T &()8. operator T &() const operator T &() constconst operator T &() const 通过这些转换运算符,通过这些转换运算符, T_varT_var 可以用于需要用到对当前使用类型的可以用于需要用到对当前使用类型的

常量或非常量用于的地方。常量或非常量用于的地方。9 T & operator[](CORBA::ULong)9 T & operator[](CORBA::ULong) const T & operator[](CORBA::ULong)constconst T & operator[](CORBA::ULong)const 如果如果 T_varT_var 表示一个序列或数组,那么就会生成下标运算符。表示一个序列或数组,那么就会生成下标运算符。

Page 46: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 6.19.2 _var6.19.2 _var 类的简单使用类的简单使用 以下是一个序列的定义:以下是一个序列的定义: typedef sequence<string> NameSeq;typedef sequence<string> NameSeq; 这样将会生成两个这样将会生成两个 C++C++ 类型:类型: NameSeq,NameSeq, 这是一个真正的序列,这是一个真正的序列,

以及以及 NameSeq_varNameSeq_var ,这是一个对应的内存管理封装函数。,这是一个对应的内存管理封装函数。 对于对于 String_varString_var ,生成的,生成的 _var_var 类型只是用于为动态分配的变长类型只是用于为动态分配的变长

度类型获取返回值。例如:度类型获取返回值。例如: extern NameSeq * get_name();//extern NameSeq * get_name();// 返回分配的堆内存句柄返回分配的堆内存句柄 NameSeq_var nsv=get_name();//nsvNameSeq_var nsv=get_name();//nsv获得所有权获得所有权 //// 不需要考虑在此释放不需要考虑在此释放6.19.3 6.19.3 使用使用 _var_var 类的一些缺陷类的一些缺陷使用使用 String_varString_var 需要注意的地方同样也适用与需要注意的地方同样也适用与 _var_var 类。如果用一个类。如果用一个

指针对指针对 _var_var 实例进行初始化或对一个指针进行赋值,那么需要确实例进行初始化或对一个指针进行赋值,那么需要确认指针确实三认指针确实三÷÷ 指向动态分配的内存,否则就会导致灾难性后果。指向动态分配的内存,否则就会导致灾难性后果。

Page 47: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 同时,将一个指针赋给同时,将一个指针赋给 _var_var 实例后,在间接引用该指针时必须加以小心。实例后,在间接引用该指针时必须加以小心。

因为对因为对 _var_var 的赋值将会释放前面使用的实例,因此会使指向该实例的指的赋值将会释放前面使用的实例,因此会使指向该实例的指针失效。针失效。

6.19.4 6.19.4 定长度和变长度的结构、联合和序列之间的区别定长度和变长度的结构、联合和序列之间的区别 在变长度类型中:在变长度类型中: 转换运算符可以用来把一个变长度的转换运算符可以用来把一个变长度的 T_varT_var 传递给需要用到对指向传递给需要用到对指向 TT 的的

指针的引用的地方。其中的成员函数可以用来将指针的引用的地方。其中的成员函数可以用来将 T_varT_var 作为作为 inin 、、 inoutinout或或 outout参数来传递,而不是缺省的类型的转换。参数来传递,而不是缺省的类型的转换。

outout 成员函数释放当前使用的类型成员函数释放当前使用的类型 TT 的实例,以避免因为相同的的实例,以避免因为相同的 T_varT_var实例连续传递给函数调用而产生内存泄漏。实例连续传递给函数调用而产生内存泄漏。

_retn()_retn() 函数指向当前的类型的函数指向当前的类型的 TT 的实例,并放弃对指针的所有权。它的实例,并放弃对指针的所有权。它主要用于创建一个主要用于创建一个 T_varT_var 实例以避免内存的泄漏,然后又必须传递对当实例以避免内存的泄漏,然后又必须传递对当前使用类型的所有权的情况。前使用类型的所有权的情况。

在定长度类型中:在定长度类型中: 附加的构造函数和赋值运算符可以用来构造附加的构造函数和赋值运算符可以用来构造 T_varT_var ,或把,或把 TT 赋给赋给 T_varT_var 。。

其中的成员函数可以用于不能正确处理缺省类型转换的编译器,同时,其中的成员函数可以用于不能正确处理缺省类型转换的编译器,同时,可以提高代码的执行效率。可以提高代码的执行效率。

用于定长度类型的用于定长度类型的 outout 和和 _retn_retn 成员函数不会放弃对当前使用类型的所用成员函数不会放弃对当前使用类型的所用权,不能这样,是因为它们不返回一个指针。权,不能这样,是因为它们不返回一个指针。

Page 48: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 6.19.5 6.19.5 数组的数组的 _var_var 类型类型 数组的数组的 _var_var 类型与结构、联合和序列的类型与结构、联合和序列的 _var_var 类型具有相同的形类型具有相同的形式,区别是数组的式,区别是数组的 _var_var 类型并不重载间接运算符,并且一些成类型并不重载间接运算符,并且一些成员函数的返回值类型也有所不同,变长和定长也不同。员函数的返回值类型也有所不同,变长和定长也不同。

包含变长元素的数组的包含变长元素的数组的 _var_var 映射映射 其中的成员函数与结构、联合和序列的其中的成员函数与结构、联合和序列的 _var_var 类型中的成员函数的类型中的成员函数的

作用完全相同。作用完全相同。 数组映射的说明数组映射的说明 (1) (1) 缺省的构造函数将指向当前使用数组的内部指针初始化为空指缺省的构造函数将指向当前使用数组的内部指针初始化为空指

针针 (2) (2) 参数为参数为 F_slice *F_slice * 的构造函数和赋值运算符都假定由的构造函数和赋值运算符都假定由 F_allocF_alloc 或或

F_dupF_dup 对数组分配内存,并且它们拥有对传递来的指针的所有权。对数组分配内存,并且它们拥有对传递来的指针的所有权。 (3) (3) 拷贝构造函数和拷贝构造函数和 F_var &F_var & 赋值运算符都进行多层次拷贝赋值运算符都进行多层次拷贝

Page 49: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 (4) (4) 析构函数通过调用析构函数通过调用 F_freeF_free 来释放数组来释放数组 (5) (5) 下标运算符允许使用数组下标,这样,下标运算符允许使用数组下标,这样, F_varF_var 就可以当作数组就可以当作数组

来使用来使用 (6) (6) 通过转换运算符可以将数组作为通过转换运算符可以将数组作为 inin 、、 inoutinout 或或 outout参数来传递参数来传递 (7) (7) 显示转换函数显示转换函数 inin 、、 inoutinout 和和 outout 与结构、联合和序列中的使用与结构、联合和序列中的使用方法一样方法一样

(8) (8) 通过通过 _retn_retn 函数可以放弃对当前使用类型的所用权 函数可以放弃对当前使用类型的所用权 所有这些意味着,可以将所有这些意味着,可以将 _var_var 数组当作正真的数组来使用,只是数组当作正真的数组来使用,只是

_var_var 数组必须通过动态分配内存来进行初始化。数组必须通过动态分配内存来进行初始化。

Page 50: 6.11  宽位字符串映射

用户定义类型和用户定义类型和 _var_var 类类 包含定长元素的数组的包含定长元素的数组的 _var_var 映射映射 包含定长元素的数组和包含变长元素的数组的包含定长元素的数组和包含变长元素的数组的 _var_var 例子之间的区例子之间的区

别是对于定长度元素,别是对于定长度元素, inoutinout 成员函数返回一个指针,而不是对成员函数返回一个指针,而不是对指针的引用,并且没有定义用于指针的引用,并且没有定义用于 StructArray_slice * &StructArray_slice * & 的用户的用户定义的转换运算符。这些区别由变长和定长在参数传递上的不同定义的转换运算符。这些区别由变长和定长在参数传递上的不同所产生。所产生。

Page 51: 6.11  宽位字符串映射