Tagged: C++ Toggle Comment Threads | 键盘快捷键

  • Roger 11:56 am on February 4, 2012 固定链接 | 回复
    Tags: C++   

    Going Native? 

    赖勇浩写了一篇文章,叫做”2012 不宜进入的三个技术点“,其中最后一个就是C++。而陈皓的”Why C++?王者归来“则表达的不同的意见,文中引述了C++界的大牛Herb Sutter的观点,认为随着计算能力再次集中在大公司构建的数据中心里面,而这些公司为了能够节约电力和机器的开销,它们有意愿,也有能力聘请高水平的工程师,使用C/C++这样的本地代码来编写它们服务端的软件堆栈。另外因为移动设备的迅猛发展,考虑电力和性能的因素,本地代码编写的应用在移动设备上仍然是最佳的选择。

     

    总的来说,我个人认为这两种观点有正确和错误的地方。下面是自己了解到的一些现实世界正在发生的真实的例子,最后再总结出自己的观点。

     

    1. NodeJS使用Google公司的V8 JS引擎(使用C++编写),构建了一个可以使用JavaScript编写服务端应用的运行时环境;
    2. 浏览器引擎如WebKit(使用C++编写)的发展,使得使用HTML/CSS/JavaScript编写能够与Native App相媲美的Web App/Game越来越成为可能;
    3. Android虽然使用了大量第三方和自家的C/C++库,平台本身的系统服务层也完全使用C++编写,但是为普通应用的编写提供了一个完整的基于Davik虚拟机,使用Java语言的应用程序框架;
    4. Windows Phone7只允许使用C#编写应用,而更换了内核的Windows Phone8虽然有可能允许使用C/C++语言,但是使用HTML+JavaScript在WinRT上编写Metro风格的应用仍然是官方主推的方式;
    5. Lua是iOS上面最热门的脚本语言,很多游戏都使用它来编写脚本,基于C++编写的游戏引擎;
    6. Qt下一代GUI框架QML,支持使用QML脚本语言构建用户界面,混合JavaScript编写的事件处理逻辑,C++编写的对象可以很容易导入JS虚拟机运行环境中。

    从上面的例子我们可以看到,毋庸置疑,C++在新的10年里面(2010+)仍然会扮演及其重要的作用,它会被用来编写各种游戏引擎,浏览器引擎,虚拟机,运行时环境,系统服务层等等,本地代码所占用的计算时间在总的计算时间中的比重有可能还会增加。

     

    但是,对于普通应用的开发者而言,无论是服务器后端,前端,还是编写本地应用,他们都将会离C/C++越来越远,需要使用的几率也越来越低,而更有可能使用各种动态语言和脚本语言。之前的一篇文章为什么学习JavaScript也阐述了自己关于JavaScript未来在各种应用开发中会越来越重要的观点。

    Advertisements
     
    • chen 10:19 上午 on 一月 4, 2013 固定链接 | 回复

      现实世界中只有C++才能工作在CPU上,所有其他语言都在一层VM上。借助VM的确可以做非常广泛的应用,但C++和CPU之间才是最直接的映射,无论如何少不了。

  • Roger 11:12 am on April 30, 2011 固定链接 | 回复
    Tags: C++,   

    段子 – Java,C++,C语言的不同 

    Java和C++的最大区别在于,Java程序员再烂,写的代码烂起来还是有底线的,而C++程序员写的代码,烂起来简直毫无底线可言,轻易就把整个系统crash 100遍啊100遍…

    而C和C++程序员的最大差别在于,C++程序员可以把自己的烂隐藏在类与对象的汪洋大海中,难以发现,而C程序员的烂如漆黑中的萤火虫,无处藏身。

     
  • Roger 11:26 am on April 16, 2011 固定链接 | 回复
    Tags: C++, Forward Declaration, Header   

    CSDN旧文 – 如何使用前置声明取代包括头文件 

    这篇文章很大程度是受到Exceptional C++ (Hurb99)书中第四章 Compiler  Firewalls and the Pimpl Idiom  (编译器防火墙和Pimpl惯用法) 的启发,这一章讲述了减少编译时依赖的意义和一些惯用法,其实最为常用又无任何副作用的是使用前置声明来取代包括头文件。

    Item 26 的Guideline – “Never #include a header when a forward declaration will suffice”

    在这里,我自己总结了可以使用前置声明来取代包括头文件的各种情况和给出一些示例代码。

    首先,我们为什么要包括头文件?问题的回答很简单,通常是我们需要获得某个类型的定义(definition)。那么接下来的问题就是,在什么情况下我们才需要类型的定义,在什么情况下我们只需要声明就足够了?问题的回答是当我们需要知道这个类型的大小或者需要知道它的函数签名的时候,我们就需要获得它的定义。

    假设我们有类型A和类型C,在哪些情况下在A需要C的定义:

    1. A继承至C
    2. A有一个类型为C的成员变量
    3. A有一个类型为C的指针的成员变量
    4. A有一个类型为C的引用的成员变量
    5. A有一个类型为std::list<C>的成员变量
    6. A有一个函数,它的签名中参数和返回值都是类型C
    7. A有一个函数,它的签名中参数和返回值都是类型C,它调用了C的某个函数,代码在头文件中
    8. A有一个函数,它的签名中参数和返回值都是类型C(包括类型C本身,C的引用类型和C的指针类型),并且它会调用另外一个使用C的函数,代码直接写在A的头文件中
    9. C和A在同一个名字空间里面
    10. C和A在不同的名字空间里面

    1,没有任何办法,必须要获得C的定义,因为我们必须要知道C的成员变量,成员函数。

    2,需要C的定义,因为我们要知道C的大小来确定A的大小,但是可以使用Pimpl惯用法来改善这一点,详情请
    看Hurb的Exceptional C++。

    3,4,不需要,前置声明就可以了,其实3和4是一样的,引用在物理上也是一个指针,它的大小根据平台不同,可能是32位也可能是64位,反正我们不需要知道C的定义就可以确定这个成员变量的大小。

    5,不需要,有可能老式的编译器需要。标准库里面的容器像list, vector,map,
    在包括一个list<C>,vector<C>,map<C, C>类型的成员变量的时候,都不需要C的定义。因为它们内部其实也是使用C的指针作为成员变量,它们的大小一开始就是固定的了,不会根据模版参数的不同而改变。

    6,不需要,只要我们没有使用到C。

    7,需要,我们需要知道调用函数的签名。

    8,8的情况比较复杂,直接看代码会比较清楚一些。

    C& doToC(C&);

    C& doToC2(C& c)  {return doToC(c);};

    从上面的代码来看,A的一个成员函数doToC2调用了另外一个成员函数doToC,但是无论是doToC2,还是doToC,它们的的参数和返回类型其实都是C的引用(换成指针,情况也一样),引用的赋值跟指针的赋值都是一样,无非就是整形的赋值,所以这里即不需要知道C的大小也没有调用C的任何函数,实际上这里并不需要C的定义。

    但是,我们随便把其中一个C&换成C,比如像下面的几种示例:

    1.

    C& doToC(C&);

    C& doToC2(C c) {return doToC(c);};
    2.
    C& doToC(C);
    C& doToC2(C& c) {return doToC(c);};
    3.
    C doToC(C&);
    C& doToC2(C& c) {return doToC(c);};

    4.
    C& doToC(C&);
    C doToC2(C& c) {return doToC(c);};

    无论哪一种,其实都隐式包含了一个拷贝构造函数的调用,比如1中参数c由拷贝构造函数生成,3中doToC的返回值是一个由拷贝构造函数生成的匿名对象。因为我们调用了C的拷贝构造函数,所以以上无论那种情形都需要知道C的定义。

    9和10都一样,我们都不需要知道C的定义,只是10的情况下,前置声明的语法会稍微复杂一些。

    最后给出一个完整的例子,我们可以看到在两个不同名字空间的类型A和C,A是如何使用前置声明来取代直接包括C的头文件的:

    A.h
    #pragma once
    #include <list>
    #include <vector>
    #include <map>
    #include <utility>
    //不同名字空间的前置声明方式
    namespace test1
    {
    class C;
    }
    namespace test2
    {
    //用using避免使用完全限定名
    using test1::C;

    class A
    {
    public:
    C   useC(C);
    C& doToC(C&);
    C& doToC2(C& c) {return doToC(c);};

    private:
    std::list<C>    _list;
    std::vector<C>  _vector;
    std::map<C, C>  _map;
    C*              _pc;
    C&              _rc;

    };

    }

    C.h
    #ifndef C_H
     #define C_H
     #include <iostream>
    namespace test1
     {
     class C
     {
     public:
     void print() {std::cout<<"Class C"<<std::endl;}
     };
     }
    #endif // C_H
     
  • Roger 12:01 am on April 12, 2011 固定链接 | 回复
    Tags: C++, , Operator overload   

    CSDN旧文 – Java 为什么没有操作符重载 

    最近一直在看Herb 的 Exceptional C++ 系列书籍 ,Scott Meyer 在书的序中写到,Exceptional C++是一本常常会”make me surprise” 的书,的确,即使使用了C++ 已经很多年,但看这样的书仍然让自己觉得对C++的理解还十分浅薄。

    但是正如不断有人提出来的这个问题 - “是系统设计的复杂程度本身需要那么多的知识,经验和技巧还是C++ 自己本身太过复杂” (嗯,我个人的理解是二者皆是 ^_^),Bruce 在 Thinking In Java 4 的序中写到,随着自己不断加深的对Java的理解,越来越了解到Java语言的设计目标就是使得描述和构建复杂系统的工作变得更容易,一个即使只有有限的知识和经验的程序员也能够使用Java来进行某种复杂程度的系统建构工作,Java就是一门更容易,能够在更高的抽象层次上描述系统的语言,也许它不那么高效,有时也显得不够灵活,但是它不会经常让你 surprise…

    回到题目的话题,Java为什么没有操作符重载,C++ 的操作符重载是其语言强大与灵活的一个重要特征, 我今年因为工作原因接触过Quatro DSP的模拟器,Quatro DSP是一个用于打印机,扫描仪的数字图象处理器,模拟器本身其实是一个C++库,通过库的支持能够把Quatro DSP的汇编语言转化为合法的C++ 函数调用,从而在C++的集成开发环境(如 VC)中模拟DSP汇编语言的执行,主要工作原理无非是将寄存器定义为某个类类型对象,从而使用宏替换和操作符重载将汇编语言变成函数调用。

    C++不但有操作符重载,还有自定义类型转换 (嗯,大多数的C++书籍都会劝你在没有正当理由的情况下千万不用去使用后者),Exceptional C++书中在讲到异常安全代码的章节中有这么一段话 ——

    “In particular, it helps to develop a habit of eyeing with mild suspicion anything that might turn out to be a function call — including user-defineed operators, user-defined conversions, and silent temporary objects among the more subtle cluprits – because any function call might throw.”

    “实际上,它会帮你养成这样的习惯,对所有语句都带着怀疑的眼光,猜测这有可能会是一个函数调用 - 包括自定义操作符,自定义类型转换,和一些更是难以捉摸的语境中悄悄产生的临时对象 - 因为函数调用就有可能抛出异常。”

    Herb写这段话的目的是为了说明在C++中写异常安全或者异常中立的代码,你必须小心分析那些语句有可能抛出异常,而一个模版代码中的大部分语句都十分有可能是一个函数调用,而函数调用就有可能抛出异常,最后剩下给你的确定不会抛出异常的语句会非常的少… … 如果你没有做好这样的心理预期,想当然的认为大多数语句都不会抛出异常,那么你被 surprise的几率就会非常之高 … …

     
c
Compose new post
j
Next post/Next comment
k
Previous post/Previous comment
r
回复
e
编辑
o
Show/Hide comments
t
返回顶部
l
Go to login
h
Show/Hide help
shift + esc
取消