精品主页 | 软件下载 | 系统下载 | 精品导航| 精彩图片 | 转帖工具 | 版主申请 | 影视下载
发新话题
打印

C /CLI中栈对象的设计问题

C /CLI中栈对象的设计问题

  


                    C  /CLI中新推出的自动确定性资源回收(Automatic deterministic destruction)被视为一个优秀的设计。是使用所谓C  /CLI这个“新瓶”来装Bjarne Stroustrup提出的RAII这个“旧酒”。



  这的确不错,相对而言,这个比C#中的using 关键字(dispose模式),以及Java中的hard-coded的dispose方法都要好许多。这个特性是由C  /CLI中栈对象(局部对象)来提供的,局部对象本身没错,RAII也是局部对象应有之义。



  但问题在于C  /CLI中栈对象的可用性由于许多原因会大打折扣,使用起来已经远远不如ISO-C  中那样流畅。下面列出了损伤其可用性的几大硬伤:



  #1、C  /CLI的栈对象并非真的位于栈中



  只要类型是ref class,C  /CLI中的栈对象就仍位于托管堆中。仍然使用newobj IL指令来分配。如果R没有定义析构器(~R)(注意:C  /CLI中的析构器和C#中的析构器完全两回事),那么下面两行代码实际上将生成完全一样的IL代码:


<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">


R r;

R h=gcnew R;</BLOCKQUOTE>


  好像记得Herb Sutter曾经说过他们将来可能会在真正的方法栈中分配r ——说实话恐怕只有C  背景的人敢这么“胡思乱想”:) 他们现在只是想在语法层面让程序员"感觉"就像r是从栈中分配的一样。又一个syntax sugar:)



  当然为了对称和语义的完美,有时候还需要在r上应用%——虽然背后仍是什么也没做:)



  #2、C  /CLI编译器默认情况下不会自动产生拷贝构造函数和拷贝赋值操作符



  这一点非常令人烦恼,几乎让人“望栈对象而却步”。更糟糕的是BCL中的所有类型都没有提供拷贝构造函数和拷贝赋值操作符——因为恐怕只有C  /CLI会用到他们。



  话说回来,即使C  /CLI会自动产生拷贝构造函数和拷贝赋值操作符,那么继承自BCL的类型还是会很麻烦。


  


                  






  #3、如果函数要被其他CLI语言调用,那么就不能将其参数设计为栈对象


a. static void add(R r){...}


  编译出来有一个modopt元数据,所以可以被其他语言调用,但是如果被其他语言调用,比如C#,那么其他语言将是以传值的方式传递引用,而C  /CLI将是传递对象拷贝(要调用拷贝构造器),所以语义混乱,完全不可以这样做。



b. static void add(R% r){...}


  由于编译出来都有一个modreq元数据,所以不能被其他CLI语言调用。



  #4、如果函数要被其他CLI语言调用,那么也不能将其返回值设计为栈对象


a. static R add(){...}


b. static R% add(){...}


  两者编译出来都有一个modreq元数据,所以都不能被其他CLI语言调用。



  #5。使用BCL时,如果要传递栈对象,总要使用“莫名其妙”的%操作符


  比如:


<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">


String s("abc");

ArrayList list;

list.Add(%s);</BLOCKQUOTE>


  实在很不好,还是使用追踪引用比较好:


<BLOCKQUOTE dir=ltr style="MARGIN-RIGHT: 0px">


String^ s="abc";

ArrayList^ list=gcnew ArrayList();

list-&gt;Add(s);</BLOCKQUOTE>


  总结一下:


  #1和#5对栈对象的可用性影响不算大,毕竟从语义层面来理解,还是行得通的。



  但是,#2、#3、#4的影响就很大。#3和#4使得我们必须放弃使用栈对象来进行互操作。而#2会让编写C  /CLI代码非常的不方便——除非你以后不想使用栈对象。


  现在的问题是,是否C  /CLI中的栈对象只是为了获得自动确定性资源回收而存在?值得这样做吗?

TOP

发新话题