西西河

主题:【原创】猛批烂书 程序员面试宝典 上 -- 晨池

共:💬64 🌺96
分页树展主题 · 全看首页 上页
/ 5
下页 末页
      • 家园 他们那本书里面,例子程序几乎是低级错误世博会

        真是叹为观止!

      • 家园 大哥,没有看懂

        这个,在我上课的时候被用于最经典的C++指针误用例子。为什么呢?我把正确的用法写出来大家应当就知道了:

        vector<CDemo> a1;

        a1.push_back(d1);

        大哥,没有看懂。这个写法和

        vector<CDemo> *a1 = new vector<CDemo>();

        a1->push_back(d1);

        delete a1;

        有什么区别吗?

        貌似晨大说的很清楚,这段代码本身没问题,而是CDemo少了拷贝构造函数的呀。

        另:晨大发的军事多,我一直以为晨大是吃飞机饭的,原来也是码代码的。。。

        • 家园 哈哈,你不是第一个认错的

          也不是最后一个,晨枫又白打了几个喷嚏,看帖不仔细害人害己不是?嘿嘿,花慰你一下

          确实最大的问题是CDemo没有拷贝构造,不过在栈里面先申请再释放,确实很无聊,就是脱裤子放屁。

          • 家园 谢花。

            先谢您的花。不过面试题嘛,还真不好计较。看他想考什么了。

            不过您的主题帖中有一点让我感兴趣,因此还想请教一下,望不吝赐教。

            我在工作中有遇到问题就是利用了Test b()这样形式的语法来解决的,简化了程序设计框架也降低了程序当中出错的可能性。

            我试着想了一想,用一个函数申明如何简化程序设计框架,可惜没想通。能给个实例么?

            • 家园 当时我们也就是利用了它构造完以后就释放的特性

              还有虚的析构函数

              本来是在很多固定的地方要依次调用很多函数(这样就串在一起写就好了),后来有的地方又要调用不同的函数,就比较麻烦了,而且不一样的还挺多,而且老变动。

              所以想了个主意是把固定要调用的放在构造函数里,不同的用不同类,放在析构函数里,要怎么调用就写对应的类。

              大概是这样,我记不太清楚了,过去有好几年了,这个只是其中之一,当时还引入了一些其他手段,比如表驱动的工厂方法等等。

              • 家园 大致知道了

                先谢谢您的说明,对我的确是一种启发。

                细细想来不过也有一些值得商榷的地方。有点剑走偏锋的感觉。与其用虚的析构函数来完成不同的调用,还不如把虚的析构函数的内容直接写成一个个的函数。这样可读性还强点,工作量也应该差不多。

                我在用C++的时候用一个原则,该编译器完成的工作让他去做,该自己干的绝不交给编译器。正如您举出的copy constructor例子一样。只要有诸如内存分配或有static的计数器变量等情况,不管3721先把拷贝构造,析构和operator=写了再说,管他用不用。因为编译器可能在你想不到的情况下会决定用他们。这也是改了自己或别人N次的bug的教训。您这种使用构造或析构属于一种implicit的方式,我更喜欢明示的方式。

                不过千万请不要误会,我绝不是说您这种方式不好。编程不高深,但有时也会有点“运用之妙存乎于心”的感觉。就好像楼下的讨论什么时候用指针,还真不好回答呢。

                • 家园 嗯……我也觉得,嘿嘿,不过细节我忘记了

                  当时这样常规的办法,肯定是考虑过的,但是没有采纳。之所以现在还记得,也是因为找了一圈,才这样用的。

        • 家园 呵呵。

          大致是如此,1是栈上分配内存,2是在堆上分配内存。

          正常情况应该是像1那么写,在栈上分配内存开销很小,执行速度很快,汇编几个指令的事情,当然函数执行结束,出栈以后,这片内存就没用了。而在堆上分配内存,就涉及到操作系统的系统调用了,像windows操作系统上的C/C++实现,动态分配内存的malloc和new一般最后会调用windows的api,用HeapAlloc在系统堆上分配内存,同样free和delete最后会调用HeapFree这个Api,把动态分配的内存释放掉。

          不过这个例子,因为STL类vector会根据塞进去东西的多少自动调整大小,分配和释放内存,在stl的实现里一般这些都是通过new,delete

          来实现,也牵涉到系统堆上内存的分配和释放,所以也很难说哪个好,当然像例子里这么简单的情况,就塞一个数进去,肯定是在栈上做比较好了。

          还有1个问题,栈的大小有限制,像早期的Windows好像就给2页还是4页,8MB还是16MB来着,记不清了,而在堆上分配内存,基本只受系统可用内存的限制,所以你即使在一个函数里,要处理很大的内存,好像也只能在堆上做。

          • 家园 不是这样的

            vector管理的对象(CDemo)的内存无论用1还是2的写法都是在堆上分配的,但a1本身在这两个写法中是有区别的。这个例子的错误之处就在a1本身的这个区别上。在绝大多数情况下,a1本身必须要放到栈上,目的是自动管理堆上内存的分配和释放,实现类似garbage collection的功能。这个例子恰恰需要这样的功能。在c++里面叫做smart pointer。不过我非常不喜欢smart pointer,因为这个玩意在绝大多数情况下,被用成了给脱裤子放屁的写法加一层保护......而且,需要在堆分配内存的情况,一般都是使用大块的内存,也就是要当成数组使用,而不是当成指针使用。但这个smart pointer却没有任何帮助数组使用书写方便的功能。

            栈的大小,缺省情况下32位系统预留1MB。16位系统应当是8~16KB吧

            • 家园 smart pointer还是很有用的

              我们公司就是大量使用,通常自己写delete语句都要被人骂的。所有的指针型变量都必须包在smart pointer里,这样做的好处就是很少担心内存泄漏的问题。

            • 家园 错误是没有的,没有所谓a1必须要放到栈上的说法。

              两个例子的区别就是,1里的vector a1是在栈上

              构造的,而2里的vetor a1是在堆上构造的。

              1里的a1在函数出栈的时候会自动调用vector类的析构函数,释放他分配的内存,同样2里的a1,在调用delete的时候,也会调用vector类的析构函数,释放他分配的内存。

              错误是没有的,当然从写法上来说是1比较好,在这种情况里2有点所谓的脱裤子放屁,而且如果你忘了写delete内存就泄露了,可1不会有这种情况,因为C++编译器在函数出栈的时候会自动调用所有临时对象的析构函数。

          • 家园 用哪一个应该是看需求

            从内存管理上来说,在堆上分配内存是不是更好?在我工作中的coding standard要求必须用new构造对象。

分页树展主题 · 全看首页 上页
/ 5
下页 末页


有趣有益,互惠互利;开阔视野,博采众长。
虚拟的网络,真实的人。天南地北客,相逢皆朋友

Copyright © cchere 西西河