Presentation is loading. Please wait.

Presentation is loading. Please wait.

第6章 基本的IDL到C++的映射 3.2 简介 从IDL到C++的映射必须具备下面的条件 (1) 映射应该很直观,并且很容易使用

Similar presentations


Presentation on theme: "第6章 基本的IDL到C++的映射 3.2 简介 从IDL到C++的映射必须具备下面的条件 (1) 映射应该很直观,并且很容易使用"— Presentation transcript:

1 第6章 基本的IDL到C++的映射 3.2 简介 从IDL到C++的映射必须具备下面的条件 (1) 映射应该很直观,并且很容易使用
(2) 应该保留常用的C++风格,尽可能像保准的C++。 (3) 应该是类型安全的。 (4) 在内存和CPU使用上应该是有效的。 (5) 必须能够用于分段或硬(非虚拟)内存的体系。 (6) 必须是可以重入的,以便能够用于线程环境。 (7) 映射必须保留位的透明性。

2 6.3 标识符的映射 IDL标识符在生成的C++代码中被保留下来。例如: enum Color{red,green,blue};
如果在IDL定义中使用了C++关键字,在映射时将在C++关键自的IDL标识符前加上_cxx_前缀,例如: enum Class{red,green,blue}; 映射为: enum _cxx_Class{red,green,blue}; 在IDL标识符中还要避免使用双下划线。因为标准从C++中将带有下划线的标识符保留为实现所用。

3 6.4 模块的映射 IDL模块被映射成C++的名字空间。IDL模块的内容在相应的C++名字空间中,因此IDL定义的作用域在C++中得以保留。例如: module Outer{ //…… module Inner{ //……};}; 映射为C++的相应的篏套名字空间。 namespace Outer{ namespace Inner{ IDL模块可以重新打开。映射为C++时,这个名字空间也可以进行再次打开。可以使用using指令来删除名字空间中变量的名称。 using namespace Outer::Inner; 对于不支持名字空间的编译器,可映射为类: class Outer{ public: //…… class Inner{ public //……};}; 以上不能使用using指令映射必须完全限定不在当前作用域的变量名称。 不能对其进行模块的再次打开。

4 6.5 CORBA模块 CORBA定义了许多标准的IDL类型和接口。为了避免破坏全局名字空间,这些定义在CORBA模块内提供。CORBA模块的映射方法与其他模块相同,因此ORB头文件中提供了一个包含对应的C++定义的CORBA名字空间。

5 6.6 基本类型的映射 IDL基本类型的映射如下所示: IDL C++ Short CORBA::Short
Long CORBA::Long Long long CORBA::Long long Unsigned short CORBA::Ushort Unsigned long CORBA::Ulong Unsigned long long CORBA::Ulong long Float CORBA::Float Double CORBA::Double Long double CORBA::Long double Char CORBA::Char Wchar CORBA::Wchar String Char * Wstring CORBA::Wchar * Boolean CORBA::Boolean Octet CORBA::Octet Any CORBA::Any

6 基本类型的映射 IDL类型往往需要使用CORBA名字空间中所定义的名称(例如,使用CORBA::long而不是long来声明一个变量)。这样同样有助于将代码转换到64位的系统上(在64位体系结构中CORBA::long定义为int)。 在映射时,IDL中的string直接映射为char *,而不是一个类型定义。原因是在OMG首先进行C++映射方面的工作时,就考虑到内存中的二进制数据布局必须在C和C++映射中是一致的。 位整数和long double类型 规范中假定当前使用的C++实现提供了对于这两个类型的本地支持,如果不支持则不能使用。 6.6.2 基本类型的重载 由于C++的重载特性,所有的基本类型在映射后都可以相互区分,唯一的一些例外是char,boolean,octet和wchar。因为char,boolean,octet类型都映射为C++的字符类型。而wchar则可以映射为C++的一种整型类型或wchar_t类型。

7 基本类型的映射 6.6.3 可以映射为char的类型 IDL的char,boolean和octet可以映射成有符号的、无符号的或一般的char类型。为了使代码具有可移植性,不要在代码中假定这些类型是有符号的或无符号的。 6.6.4 wchar的映射 IDL的wchar可以映射为C++的整数类型,或映射为C++的wchar_t。 6.6.5 Boolean映射 在标准的C++中,被映射为bool,不能这样做。在老的C++中,CORBA::Boolean映射为普通的char,signed char或unsigned char。 为了是代码具有可移植性,用1和0来作为布尔量。 6.6.6 字符串和宽位字符串映射 字符串被映射为char *,宽位字符串映射为CORBA::Wchar *。 字符串在动态分配时使用new和delete不太方便,可以使用辅助函数。

8 基本类型的映射 Namespace CORBA { //…… static char * string_alloc(Ulong len);
static char * string_dup(const char *); static void string_free(char *); static Wchar * wstring_alloc(Ulong len); static Wchar * wstring_dup(const Wchar *); static void wstring_free(Wchar *); //……} 以上的函数用来处理字符串的宽位字符串的动态内存分配。当然由动态库分配的内存必须由同样的库来回收内存。 string_alloc函数分配的内存比len参数所要求的多1个字节。 char * p=CORBA::string_alloc(5); Strcpy(p,”Hello”); 用string_dup来写更为简单。 char * p=CORBA::string_dup(“Hello”);

9 基本类型的映射 如果内存分配失败的话,返回一个空指针,并不发送异常。
必须用xtring_free来释放string_alloc和string_dup分配的内存,对一个空指针调用string_free是安全的。 Wstring *辅助函数在语义上于string *相同。

10 6.7 常量的映射 全局的IDL常量映射为文件域的C++常量,而篏套在一个接口内部的IDL常量映射为静态类域的C++常量,例如:
const long Max_E=10; interface Namelist{ const long Mac_N=20;}; 映射为: const CORBA::long Max_E=10; public: static const CORBA::long Mac_N;或者 static const CORBA::long Mac_N=20;}; 保留了作用域的篏套,但是这意味着篏套的接口内部的IDL常量并不是C++的编译时常量。在老的C++中,对静态类成员的初始化是在存根文件中生成一个初始化语句。而在标准C++中,则允许在类的头文件中对整型和枚举型的常量类成员进行初始化。

11 6.7 常量的映射 通常,各个变量的初始化是互不相关的。 char * enter_array[Max_E];// ok
char * names_array[Namelist::Max_N];// error 可以通过使用动态分配来避免这种限制,不管IDL编译器是否可以映射常量,动态分配都有效。 char * * names_array=new char * [Namelist::Max_N];// ok 字符串常量映射为指向常量数据的常量指针: const string MSG1=“hello”; const wstring MSG2=L“world”; 映设如下: 为全局范围内: const char* const MSG1=“hello”; const CORBA::Wchar * const MSG2=L“world”; 为interface messages内的局部常量: class Messages{ public: static const char* const MSG1”; static const CORBA::Wchar * const MSG2”;

12 6.7 常量的映射 如果IDL常量在一个模块中(而不是一个接口)说明的话,它们的映射取决域使用的是老的C++还是标准的C++编译器。例如:
module MC{ const string Greeting=“Hello”; const double PI=3,.14;} 老的C++中: class MC{ static const char * Greeting; static const CORBA::double PI;} 标准的C++中,映射为一个名字空间和常量都放置在生成的头文件里: namespace MC{ const char* Greeting=“Hello”; const CORBA::double PI=3,.14;}

13 6.8 枚举类型的映射 IDL枚举类型映射为C++的枚举类型。枚举在映射时不发生变化,除了添加一个枚举值,以使枚举成为一个32位的类型。例如: enum Color{red,green,black}; 映射为: enum Color{red,green,black,_Color_dummy=0x }; 其中red为0,green为1,balck为2。但这只适用于C++。而在传递时还是不能传递值。

14 6.9 变长度的类型与_var类型 IDL支持许多变长度类型,入字符串和序列。变长度的类型有一些特殊的映射要求。因为变长度的数值大小在编译过程中时未知的,它们必须在运行过程中进行动态分配。对程序员来说,由于需要对内存进行管理,就产生了如何动态分配与动态释放方面的问题。 C++的映射在两个不同的层次上进行。 在低层次上:需要负责所有内存的管任务。可以在这一层次中编写代码,但是必须记住在什么样的情况下,需要动态分配与释放内存。在此次层次上的映射还会导致对于定长度和变长度的结构类型在内存管理规则上的不同。 在高层次上:由于通过了一组灵巧的指针类,即_var类型,因此C++映射就变得非常简单和安全。_var类型可以使你不用考虑显示释放变长度的变量,因此就不可能产生内存的泄漏情况。这些类型弥补了定长度与变长度的结构类型之间的差别。因此不需要考虑作用域这些变量的内存管理规则之间的不同。

15 _var类型的使用 编写一个C函数,用它从I/O设备中读取一个字符串,并将该字符串返回给调用它的程序。字符串的长度没有限定,预先不知道。
解决此问题的方法很多,每一种都各有有缺点: 方法1:静态内存 const char * get_string(){ static char buf[1000];//足够大 /*读字符串进入buf */ return buf;} 此方法的优点时简单,其缺点如下: 返回的字符串可能比预计的要长。 对于短的字符串,函数会浪费内存。 每次调用get_string都会改写上次调用的结果。 函数是不能重入的。如果多个线程调用,则相互修改。

16 _var类型的使用 方法2:指向动态内存的静态指针 const char * get_string(){
static char * result=0; static size_t rsize=0; static const size_t size_of_block=512; size_t rlen; rlen=0; whlie(data_remains_to_be_read()) { /*读数据块*/ if(rsize-rlen<size_of_black){ rsize+=size_of_block; result=realloc(result,rsize);} /*追加数据块到结果集中*/ rlen+=size_of_block;} return result;}

17 _var类型的使用 这种方法使用了一个指向动态内存的静态指针,从而生成一个用于保存数据必需的缓冲区。此方法可避免字符串长度的限制,可是还是会对其结果进行改写,函数不可重入。还是会浪费内存,因为程序会按照最坏的情况来分配并占有内存。 方法3:由调用程序分配内存: size_t; get_string(){ /*读最大的尺寸到结果集中*/ return number_of_bytes_read;} 此方法是UNIX read系统调用中所采用的方法。可重入、不会超出内存或强制截断、对内存进行有效管理。 缺点:如果字符串比提供的缓冲区长的话,那么调用程序就需要不断调用函数,直到读完为止。

18 _var类型的使用 方法4:返回指向动态内存的指针 const char * get_string(){
static char * result=0; static size_t rsize=0; static const size_t size_of_block=512; size_t rlen; rlen=0; whlie(data_remains_to_be_read()) { /*读数据块*/ rsize+=size_of_block; result=realloc(result,rsize);} /*追加数据块到结果集中*/ return result;} 缺点是:调用程序需要释放函数的返回结果。

19 _var类型的使用 6.9.2 变长度类型的内存管理 以上的 方法1和方法2不适用于C++的映射,因为它们是不可重入的,方法3也是不适合的,因为如果调用程序与被调用程序在不同的机器上,重复调用的代价会很大。 变长度类型的C++映射采用方法4,C++映射使调用程序负责在不需要变长度的返回结果时,将它释放掉。 根据定义,在IDL中被认为是变长类型的有: 字符串和宽位字符串(有界或无界) 对象引用 any类型 序列 包含变长类型的结构或联合 包含变长类型的数组 对于定义中的每个结构的IDL类型,IDL编译器都生成一对C++类型,例如联合foo,编译器就会生成两个C++类,类foo和类foo_var。ooo提供了所有用于联合的函数,以及与底层映射有关的函数。类foo_var则通过类foo的内存管理封装类的方式提供高层映射。尤其是,如果类foo表示一个IDL变长度类型的话,类foo_var则会负责在适当的时候释放类foo实例。

20 _var类型的使用 IDL类型与C++类型的对应关系如下: IDL类型 C++类型 封装C++类型 String Char *
CORBA::Strinf_var Any CORBA::any CORBA::any_var Interface foo Foo_ptr Class foo_var Struct foo Union foo Class foo Typedef sequence<X> foo Typedef x foo[10] Typedef X foo[10]

21 _var类型的使用 注意: 结构、联合和数组可以是定长度或变长度的。即使对应的IDL类型是定长度,IDL编译器也会生成一个_var类。对于定长度的类型,其对应的_var类实际上并没有什么用处。主要用来弥补定长度类型与变长度类型在内存管理上的差别。

22 6.10 String_var封装类 类CORBA::String_var为char *提供了一个内存管理封装类,在此类中有一个字符串指针,用来管理字符串的内存。 class String_var{ public: String_var(); String_var(char *); String_var(const char *); ~String_var(); //…… private: char * s; }

23 String_var封装类 String_var定义如下: Class String_var{ Public: String_var();
String_var(char *); String_var(const char *); String_var(const String_var & s); ~String_var(); String_var & operator=(char * p); String_var & operator=(const char * p); String_var & operator=(const String_var & s); operator char * (); operator const char * () const; operator char * & (); Char & operator[](Ulong index); Char operator[](Ulong index) const; Const char * in() const; Char * & inout(); Char * & out(); Char * _retn(); };

24 String_var封装类 逐个函数解释如下: String_var()
CORBA::String_var s; count<<s<<endl;//错误 String_var(char *) 此函数用所传递的字符串对String_var进行初始化。String_var负责处理字符串。用动态分配的字符串对String_var进行初始化,不需要考虑显示释放字符串的问题。当String_var离开作用域时,它会自己处理内存释放问题。例如: { CORBA::String_var s(CORBA::string_dup(“hello”)); //…… } //没有内存遗漏,~string_var()调用string_free()

25 String_var封装类 String_var(const char *)
使用const char *构造函数对String_var进行初始化时,String_var就会对字符串进行多层次拷贝。当String_var离开作用域后,就会释放字符串拷贝,但却不会改变原有的拷贝。例如: const char* message=“hello”; //…… { CORBA::String_var s(message);//深层次拷贝 } //~String_var释放自己的拷贝而已 cout<<message<<endl;//ok

26 String_var封装类 String_var(const String_var &)
析构函数调用CORBA::string_free来释放由String_var所保存的字符串。 String_var & operator=(char * p); String_var & operator=(const char * p); String_var & operator=(const String_var & s); 此三个函数为赋值运算符。赋值运算符遵循构造函数的使用方法。Char *赋值运算符在假定字符串由string_alloc或string_dup进行内存的分配前提下使用,并且拥有对字符串的所有权。 const char *和String_var赋值运算符都进行多层次拷贝。 在接收新的字符串之前,赋值运算符首先释放由目标保存的当前的字符串。例如:

27 String_var封装类 CORBA::String_var target;
target=CORBA::string_dup(“hello”);//target得到所有权 CORBA::String_var source; source=CORBA::string_dup(“hello”); //source得到所有权 target=source;//释放“Hello”和深层次拷贝获得“world”的所有权

28 String_var封装类 operator char * (); operator const char * () const; 这些转换运算可以把String_var转换为char *或const char *。例如: CORBA::String_var s; s=get_string();//get_string()用string_alloc()分配内存, //s获得所有权 size_t len; len=strlen(s); //函数strlen需要const char *参数,但在此也是成功的。 转化运算符允许将String_var透明地传递给需要用char *或const char *作为参数的IDL运算符。

29 String_var封装类 Operator char * &()
此转换函数可以通过一个标记传递一个对函数进行修改的字符串,下面就是一个这样的标记: void update_string(char * &); 转换成指针的引用是必要的,这样的话,被调用函数就可以增加字符串的长度。指针引用可以从函数中传递出来,因为增加字符串传递需要再次分配内存,这样就意味着指针值需要更改,而不是指针所指向的字节需要被更改。

30 String_var封装类 CORBA::String_var s=CORBA::string_dup(“Hello”);
Char & operator[](Ulong index); Char operator[](Ulong index) const; 此函数使用来重载下标的,重载下标运算符的作用是通过下标可以得到String_var的各个字符,就像String_var是数组一样。例如: CORBA::String_var s=CORBA::string_dup(“Hello”); cout<<s[4]<<endl;//打印出‘o’ 字符串的下标就像普通的数组一样,从0开始。s[5]是合法的,它返回字符串结束为的空字节。超出下标,错误。

31 使用String_var的缺陷 类String_var的作用主要是解决返回值和用于运算符调用的out参数问题,效率低。缺陷如下: 1.字符串字面值的初始化或赋值 字符串类型在老的C++中是char *,但在标准的C++中是const char *。如果使用老的C++,下面的代码肯定会使系统崩溃。 CORBA::String_var s1(“Hello”); //崩溃灾难 CORBA::String_var s2=“Hello”; //崩溃灾难 s1和s2都由构造函数进行初始化。问题是由那个函数进行初始化。

32 使用String_var的缺陷 在老的C++中,字符串的类型是char *。因此编译器就会调用char *构造函数,而这个构造函数就拥有对所传递的字符串的所有权。当s1和s2撤消时,析构函数就会调用string_free,其参数就是初始化数据段的地址。当然,释放不是堆的内存会导致出现一些不可预料的事情。 同样问题会出现在向String_var分配一个字符串字面值时: CORBA::String_var s3; s3=“Hello”;//调用operater=(char *),崩溃灾难

33 使用String_var的缺陷 并使String_var管理拷贝,或者通过将其转换成const char *的方法创建一个多层次拷贝。例如:
CORBA::String_var s1((const char *)”Hello”);//深层次拷贝 CORBA::String_var s2(CORBA::string_dup(”Hello”));//显式拷贝 CORBA::String_var s3=(const char *)”Hello”;//深层次拷贝 CORBA::String_var s4=CORBA::string_dup(”Hello”);//显式拷贝 CORBA::String_var s5 s5=(const char *)”Hello”;//深层次拷贝 CORBA::String_var s6 s6=CORBA::string_dup(”Hello”);//显式拷贝 const char * p=“Hello”;//定义一个静态的字符串指针 CORBA::String_var s7(p); //深层次拷贝 CORBA::String_var s8=p; //深层次拷贝 CORBA::String_var s9; s9=p; //深层次拷贝

34 使用String_var的缺陷 以上是对字符串字面值进行初始化和赋值的不同方法。任何时候,每个String_var变量都随着字面值自身拷贝的消亡而消亡,而字面值的拷贝可以由析构函数来释放。 如果出现转换成const char *的情况,构造函数或赋值运算符就会生成一个多层次的拷贝。如果调用了string_dup,就会显式创建一个字符串字面值的拷贝,并且String_var会负责释放这个拷贝。 这两种方法都正确,可是倾向于使用string_dup,而不是强制转换。 对于标准的C++,下面是正确的: CORBA::String_var s=“Hello”;

35 使用String_var的缺陷 2. 将String_var赋给指针
如果将String_var变量赋值给char *或const char *变量,赋过值的指针会指向在String_var内部的内存。这就意味着在使用这样赋值后的指针时需要注意。例如: CORBA::String_var s1=CORBA::string_dup(“Hello”); const char * p1=s1; //浅赋值 char * p2; { //…… CORBA::String_var s2=CORBA::string_dup(“world”); p2=s2; //浅赋值 s1=s2; //释放“Hello”,深层次拷贝“world”} cout<<p1<<endl;//p1指针没有所指 cout<<p2<<endl;//p2指针没有所指 上面代码出现了两个常见错误,错误的原因在于将一个String_var赋值给一个指针的过程是一个浅赋值。

36 使用String_var的缺陷 第一个指针的赋值(p1=s1)使p1指向由s1所占据的内存。s1=s2是一个深层次赋值,它会释放s1(“Hello”)的初始值。11的值不会受到影响,因此p1现在指向已经释放的内存。 第二个指针的赋值(p2=s2) 也是一个浅赋值,因此p2指向由s2所占据的内存。当s2离开作用域时,它的析构函数会释放这个字符串,这样就使p2指向了已经释放的内存。 这并不是意味着任何情况下都不要把String_var赋值给一个指针。然而,如果进行这样的操作赋值,并且想要使用这个指针的话,必须确保这个指针指向的字符串不能由赋值或析构函数来释放。

37 将字符串作为传递参数以读取字符串 一些函数往往以字符串作为参数,以便读取字符串。程序中往往还会出现char *类型和String_var类型变量,在此给出一个比较。 void print_string(CORBA::String_var s){ cout<<s<<endl;} main(){ CORBA::String_var msg1=CORBA::string_dup(“hello”); print_string(msg1); return 0;} 这段代码使正确的,但效率很低。在执行函数print_string时,要调用多大10个的函数,而且还会出现一下问题: print_string(“world); //调用的是char *,崩溃灾难

38 将字符串作为传递参数以读取字符串 如果用以下这段代码就好多了: void print_string(const char * s){
cout<<s<<endl;} int main(){ CORBA::String_var msg1=CORBA::string_dup(“hello”); print_string(msg1); print_string(“world”);// return 0;} 实际上参数是String_var类型,编译器通过const char *转换运算符进行函数的调用。转换运算符返回String_var内部的私有指针,并且往往是内联的,也就使调用的时间降低到最小。

39 将字符串作为传递参数以更改字符串 在进行更改时,不能使用String_var &类型。将char *类型的字符串传递给String_var &类型的参数时,编译器会创建一个临时拷贝。这就会导致用char *字面值去构建String变量,最终将出现核心转存的情况。为了解决这一问题,必须使用char * &参数类型。例如:

40 将字符串作为传递参数以更改字符串 void upate_string(char * & s){ CORBA::string_free(s);
s=CORBA::string_dup(“New string”); } int main(){ CORBA::String_var sv=CORBA::string_dup(“Hello”); update_string(sv); cout<<sv<<endl;//成功,打印“New string” char * p=CORBA::string_dup(“Hello”); update_string(p); cout<<p<<endl; //成功,打印“New string” CORBA::strin_free(p) return 0;}

41 将字符串作为传递参数以更改字符串 update_string假定它所传递的字符串是由string_alloc或string_dup进行内存分配的,这就意味着下面的代码是不可移植的: char* p=new char[sizeof(“Hello”)]; strcpy(p,”Hello”); update_string(p);//错误 delete[] p; 这段代码会导致由new分配的内存被string_free所释放,而由string_dup所分配的内存被delete所释放,是错的。 调用参数中有未初始化指针的update_string也会产生问题,因为这回导致将未初始化的指针传递给string_free,很可能出现灾难型错误,然而,传递一个初始化为空的变量是安全的,向string_free传递一个空指针意味着strinf_free什么都不做。

42 隐式类型转换产生的问题 将String_var传递给char *类型需要进行隐式类型的转换。一些编译器不能正确地使用转换运算符,或者会不接受不明确地调用。C++映射并不期望每个C++编译器都是完美地,相反它提供了一些成员函数,这些成员函数可以允许进行显式类型地转换。这些成员函数是in,inout,out和_rent(这些名称表示参数传递地方向)。

43 隐式类型转换产生的问题 CORBA::String_var msg1=CORBA::string_dup(“hello”);
const char * in() const 如果编译器不能将String_var类型传递给const char *类型,那么就可以调用该转换函数。例如: void print_string(const char * s){/*……*/} CORBA::String_var msg1=CORBA::string_dup(“hello”); print_string(msg1);//有些编译器不能处理 print_string(msg1.in());//显示调用,避免错误 in成员函数以const char *类型返回String_var封装类中保存的私有指针也可以通过强制转换来实现。 print_string((const char *)sv);

44 隐式类型转换产生的问题 char * & inout()
此函数返回一个对String_var封装类保存的指针引用,以便可以改变String_var的值。 char * & out() out函数于inout函数的区别在于:out在返回一个对空指针的引用之前释放字符串。

45 隐式类型转换产生的问题 void read_string(char * & s)//是一个out参数 { //从文件里读一行
{ //从文件里读一行 s=CORBA::string_dup(line_of_text):} 调用程序可以在不产生内存泄漏的情况下使用read_string,如下: CORBA::String_var line; read_string(line.out));//读第一行 read_string(line.out));//读第二行,没有内存泄漏 cout<<line<<endl;//打印第二行 调用out成员函数要做两件事情:首先释放由String_var当前保存的字符串,然后返回一个指向一个空指针的引用。这样,调用程序就会在没有内存泄漏的情况下在一行中两次调用read_string。同时,read_string不需要在分配一个新的数值之前释放字符串。(释放也不会有问题,因为释放一个空指针也是安全的。)

46 6.10.5 取得对字符串的所有权 _retn成员函数返回由String_var保存的指针,同时也取得了对字符串的所有权。
for(int I=0;I<num_line;i++){ CORBA::String_var line=get_line(); cout<<line<<endl;} get_line函数动态分配返回的字符串,并且使调用程序负责释放,调用程序通过捕获String_var变量line来响应。 下面使get_line函数的大致内容。这里重要的一点是get_line可能在分配字符串之后产生一个异常。

47 取得对字符串的所有权 char * get_line(){ //打开数据库连接和读字符串进入buffer //给字符串分配内存
CORBA::String_var s=CORBA::string_dup(buffer); //关闭数据库连接 if(db.close()=ERROR){ //出现错误 throw DB_CloseException();} //成功,返回字符串 return s._retn();} 变量s是一个String_var。如果在给s分配内存后发送了一个异常,那么就不用担心内存泄漏的问题,编译器会在清空栈以响应异常时,调用s的析构函数。

48 取得对字符串的所有权 在不出错的情况下,get_line返回一个字符串,并且由调用程序来管理这个字符串。这就意味着get_line并不只是简单地返回s,因为接下来的话,字符串会被错误地释放两次,第一次是被s的析构函数,第二次是被调用程序。 get_line中的最后一条语句也可以如下所示: return CORBA::string_dup(s); 这条语句是正确的,但是会对字符串进行不必要的拷贝,通过调用_retn成员函数,get_line就把释放s的责任交给调用程序,通过这种方法可以避免对字符串进行拷贝。

49 6.10.6 流运算符 C++映射为C++的iostreams提供了重载的String_var插入和提取运算符。
CORBA::String_var s=…; cout<<“String is\””<<(s!=0?s:””)<<“\””<<endl; cin>>s; cout<<“String is now\””<<(s!=0?s:””)<<“\””<<endl; 这些重载运算符是为istream和ostream提供的,因此它们也可以用于字符串(strstream)类和文件(fstream)类。

50


Download ppt "第6章 基本的IDL到C++的映射 3.2 简介 从IDL到C++的映射必须具备下面的条件 (1) 映射应该很直观,并且很容易使用"

Similar presentations


Ads by Google