C ++比D有什么优势?


135

我最近一直在学习D,并且开始对这种语言有所了解。我知道它提供了什么,我还不知道如何使用所有东西,并且我对D习语等不了解很多,但是我正在学习。

我喜欢D。这是一种很棒的语言,以某种方式对C进行了巨大的更新,并且做得很好。似乎没有一个功能可以“实现”,但实际上是经过深思熟虑和精心设计的。

您会经常听到D是C ++ 应该是的(我要问的是每个人都应该自己决定是否这样做,以避免不必要的火焰战争)。我还从几位C ++程序员那里听说,他们对D的喜欢远超过C ++。

我自己,虽然我知道C,但是我不能说我知道C ++。如果有人认为C ++比D 作为语言要好,那我想听听他们都知道C ++和D的东西(这不是通常的“它具有更多的第三方库”或“有更多的资源”或“需要C ++的工作多于D”。)

D是由一些非常熟练的C ++程序员(在D社区的帮助下)由Walter BrightAndrei Alexandrescu设计的,旨在解决C ++所遇到的许多问题,但是到底有没有真正变得更好的东西?他错过了什么吗?您认为不是更好的解决方案吗?

另外,请注意,我所说的是D 2.0,而不是D 1.0


15
我确保D社区确实看到了这一点,因为我确信C ++开发人员比D开发人员多得多。这样,您将获得更多有趣的答案,或者至少会有各种各样的答案。
克拉姆2011年

7
同样,D2由Walter Bright设计,但也由Alexandrescu设计。您可能要解决您的问题。
Klaim

2
@Klaim:在(现在仍然)有很多社区参与D和标准库。
Michal Minich 2011年

28
@Anto作为一种语言,C ++在使您(程序员)讨厌您的生活方面比D要好得多。
阿伦

6
@jokoon:的确,是的,几乎没有什么工作:digitalmars.com/d/2.0/interfaceToC.html
Anto

Answers:


124

C ++比D更好的大多数事情都是元数据:C ++具有更好的编译器,更好的工具,更成熟的库,更多的绑定,更多的专家,更多的教程等。基本上,它拥有越来越多的外部事物。会期望使用更成熟的语言。这是无可争辩的。

至于语言本身,在我看来,C ++在某些方面比D更好。可能还有更多,但我可以列举几个:

C ++具有更好的思想类型系统
目前,D中的类型系统存在很多问题,这些问题似乎是设计中的疏忽。例如,由于const的可传递性和postblit构造函数在值类型上的工作方式,如果该struct包含类对象引用或指针,则当前无法将const struct复制到非const结构。安德烈(Andrei)说他知道如何解决这个问题,但没有透露任何细节。这个问题当然是可以解决的(引入C ++样式的副本构造函数将是一个解决方法),但这是当前语言上的一个主要问题。

困扰我的另一个问题是缺少逻辑常量(即,mutable与C ++ 不一样)。这对于编写线程安全代码非常有用,但是很难(不可能吗?)在const对象中进行惰性初始化(想像一个const'get'函数,该函数在第一次调用时构造并缓存返回的值)。

最后,考虑到这些存在的问题,我很担心如何类型系统(其余部分pureshared等)将与所有的语言否则一旦被投入使用互动。标准库(Phobos)目前很少使用D的高级类型系统,因此我认为在压力下是否可以承受这个问题是合理的。我对此表示怀疑,但很乐观。

请注意,C ++有一些类型系统疣(例如,非传递性const,需要iteratorconst_iterator),这使其很难看,但是C ++的类型系统在某些方面有一些错误,但这并不能阻止您像D一样完成工作。有时会。

编辑:为澄清起见,我相信C ++具有更好的思想类型系统-不一定是更好的类型系统-如果可以的话。本质上,在DI中,使用C ++中没有的类型系统的所有方面都存在风险。

D有时太方便
了。您经常听到的C ++批评是它隐藏了一些低级问题,例如,简单的赋值a = b;可能会做很多事情,例如调用转换运算符,调用重载赋值运算符等,这可能是从代码中很难看到。有些人喜欢,有些人不喜欢。无论哪种方式,在d更是雪上加霜(更好?)因为喜欢的事物opDispatch@propertyopApplylazy这不得不改变无辜的看着代码到的东西,你不希望的潜力。

我个人认为这不是一个大问题,但有些人可能会觉得这令人反感。

D需要进行垃圾收集
这可能会引起争议,因为可以在不使用GC的情况下运行D。但是,仅仅因为有可能并不意味着它是实用的。没有GC,您将失去许多D的功能,使用标准库就像走在雷区(谁知道哪个函数分配内存?)。就我个人而言,我认为在没有GC的情况下使用D是完全不切实际的,如果您不喜欢GC(如我),那么这可能会令人反感。

D中的朴素数组定义分配内存
这是我的烦恼:

int[3] a = [1, 2, 3]; // in D, this allocates then copies
int a[3] = {1, 2, 3}; // in C++, this doesn't allocate

显然,为了避免在D中进行分配,您必须执行以下操作:

static const int[3] staticA = [1, 2, 3]; // in data segment
int[3] a = staticA; // non-allocating copy

这些很少的“背后隐藏”配置是我前面两点的很好例子。

编辑:请注意,这是一个正在解决的已知问题。
编辑:现在已修复。没有分配发生。

结论
我一直专注于D vs C ++的缺点,因为这是要问的问题,但是请不要将此帖子视为C ++比D更好的陈述。比C ++ 由您决定使用哪一个。


几年前(2.0之前),我看了看D。那时实际上并不需要垃圾收集-默认情况下存在垃圾收集,但是您可以选择不使用低级代码。我认为这是错误的,因为我找不到办法选择退出。例如,在基于树的容器中,库代码可以管理树节点本身的内存。整个树仍然可以被收集,使用IIRC的析构函数收集所有这些节点。但是该容器中数据引用的对象也应该是可收集的-应该有一个钩子来标记树中GC的所有数据项。
Steve314 2011年

3
您仍然可以为低级代码禁用GC-彼得说,目前的语言在很大程度上取决于它。另外,您可以使用其API:core.memory中的GC.addRange告诉GC扫描其托管堆之外的范围。
弗拉基米尔·潘捷列夫2011年

+1指出D标准库是垃圾回收,并且GC-off代码不是无缝互操作。这不是我考虑过的事情,但这似乎是克服的主要障碍。
masonk

132

当我加入D开发时,我身为最了解C ++的人之一。现在,我处于更加特殊的位置,成为最了解D的人之一。我并不是在说这是对适当的信誉或吹牛的权利,而只是说我很好奇有利位置来回答这个问题。沃尔特也是如此。

总的来说,问C ++(和C ++ 2011)比D做得更好是一个自相矛盾的问题,即“如果您付钱请专业人士来打扫房屋,他们将离开哪里?比以前更脏?” C ++可以做到D不能做到的任何价值,对我和Walter而言,它始终像是一个痛苦的拇指,因此从定义上来说,几乎没有C ++可以做到的事情不在D的范围之内。

在语言设计中很少理解的一件事(因为很少有人能真正做到一些运气)是非强制错误的数量比可能出现的要少得多。我们中的许多语言用户都在看某个或另一个结构,然后说:“噢!这太错了!他们在想什么?” 事实的事实是,语言中最尴尬的事例是一些基本决定的结果,这些基本决定都是合理和可取的,但在根本上是相互竞争或矛盾的(例如,模块化和效率,简洁性和控制性等)。

考虑到所有这些,我将列举一些我能想到的事情,并且针对每件事,我都会解释D的选择是如何从满足其他更高层次的章程的愿望中得到的。

  1. D假定所有对象均可按位复制。这给C ++留下了很少的设计,特别是那些使用内部指针的设计,即,内部包含指针的类。(可以将这种设计免费转换为D或将效率转换为零,但是会涉及翻译工作。)我们做出这一决定是为了大大简化语言,使对象复制更加有效,而无需用户干预或只需很少的干预,并避免整个副本构建过程和右值引用都具有相同的功能。

  2. D禁止使用含糊不清的性别类型(无法确定它们是值类型还是引用类型)。此类设计在C ++中被一致避免,并且几乎总是错误的,但是其中一些在技术上是正确的。我们之所以选择该选项,是因为它不允许大多数不正确的代码,只有很小一部分可以重新设计的正确代码。我们认为这是一个很好的权衡。

  3. D禁止多根层次结构。之前的海报对此非常感兴趣,但这是一个广为人知的基础,与拥有共同根源的层次结构相比,无根层次结构没有明显的优势。

  4. 在D中,您不能抛出例如int。您必须抛出继承Throwable的对象。毫无疑问,D中的事务状态会更好,但是,C ++可以做到D不能做到的一件事。

  5. 在C ++中,封装单位是一个类。在D中,它是一个模块(即文件)。Walter做出此决定的原因有两个:将封装自然地映射到文件系统保护语义,以及消除对“朋友”的需要。这个选择很好地集成在D的整体模块化设计中。可以将事物更改为更像C ++,但这将迫使事物产生变化。C ++的封装范围选择仅对C ++的物理设计有用。

可能有一两个较小的东西,但总的来说应该是这样。


6
@DeadMG:要在C ++中工作,要移动的对象将需要指向该对象的后向指针(以便它可以在复制构造期间更新)。在这种情况下,无论如何,您可以在D中使用postblit构造函数更新指针。如果您仅对D有了解,请不要反对。
彼得·亚历山大

13
@Peter:即使生命周期严格基于范围,也应该作为参考?我应该浪费动态分配它的开销以及间接,缓存和收集的开销,因为我想给它起别名?另外,我希望收集器可以确定性地收集它,以获得等效的语义。显然,这是不受控制的。
DeadMG

3
@sbi:顶级人士的存在根本不会影响您的选择。在类类型的晶格中,始终存在顶部和底部。底部仅在几种语言中是显式的。顶部(即对象等)在更多语言中是显式的。这些类型在概念上始终存在。当它们也可以访问时,它们只是为语言的用户提供了一些额外的功能而不会造成麻烦。
Andrei Alexandrescu

6
@quant_dev:您会很高兴听到已经有一个状态良好的GSoC项目,该项目专注于使用BLAS的高性能线性代数。它还提供用于测试和基准测试目的的适当基元的“原始”实现。为了回答您的第二个问题,Java将比较数字库的标准设置得很低。它总是要克服访问高性能代数库的JNI障碍,并且语法会很糟糕,因为Java缺少运算符重载。
Andrei Alexandrescu

4
@PeterAlexander:DeadMG恰到好处。“您不应该使用指向值类型的指针”显然忽略了以下事实:任何语言中的指针通常都与值类型一起使用(您是否真的希望看到与Object*as一样广泛使用的指针int*),而D似乎完全忽略了这一事实。性能损失或声称不存在。这显然是错误的-在许多情况下,高速缓存未命中非常明显,因此C ++始终比D具有更大的灵活性优势
。– Mehrdad

65

我认为您很难在D中找到很多东西,客观上比C ++差。您可以客观地说出更糟糕的D问题,大多数是实施质量问题(通常是由于语言和实施还很年轻,并且已经以极快的速度被解决),或者是问题缺少第三方库(随时间推移而来)。语言本身通常比C ++更好,并且C ++作为一种语言更好的情况通常是在权衡的情况下C ++沿一种方式而D沿另一种方式进行,或者有人对其产生主观原因认为一个比另一个更好。但是,作为一种语言,C ++更好的直接客观原因的数量可能很少而且相差甚远。

实际上,我必须绞尽脑汁想出C ++作为一种语言优于D的原因。通常我想到的是权衡问题。

  1. 因为D的const是可传递的,并且由于语言是不可变的,所以它比C ++的保证要强得多const,这意味着D没有并且不能拥有mutable。它不能具有逻辑const。因此,使用D的const系统可以获得巨大的收益,但是在某些情况下,您将无法const像在C ++中那样使用。

  2. D仅具有一个强制转换运算符,而C ++具有4(如果计算C强制转换运算符则为5)。在通常情况下,这使处理D中的强制转换更为容易,但是当您实际上想要const_cast由其及其弟兄提供的额外的复杂性/好处时,这是有问题的。但是D实际上足够强大,您可以使用模板来实现C ++的强制类型转换,因此,如果您真的想要它们,则可以拥有它们(它们有时甚至可以最终出现在D的标准库中)。

  3. D具有比C ++更少的隐式强制转换,并且更有可能声明两个函数彼此冲突(迫使您更确切地说明要使用的函数-强制转换或提供完整的模块路径) )。有时,这可能很烦人,但是它可以防止各种功能劫持问题。您知道您实际上在调用您想要的功能。

  4. D的模块系统是远远超过C ++的#包括清洁剂(不提,这样速度更快的编译),但它缺乏任何类型的命名空间超出模块本身的。因此,如果要在模块中使用命名空间,则必须走Java路线,并在类或结构上使用静态函数。它可以工作,但是如果您真的要使用命名空间,则显然不如真正的命名空间干净。但是,在大多数情况下,模块本身为您提供的命名空间足够多(在涉及诸如冲突之类的东西时相当复杂)。

  5. 像Java和C#一样,D具有单一继承而不是多重继承,但是与Java和C#不同,它为您提供了一些奇妙的方式来获得相同的效果,而没有C ++的多重继承所带来的所有问题(而且C ++的多重继承会变得非常混乱有时)。D不仅具有接口,而且具有字符串混合器模板混合器别名。因此,最终结果可以说更强大,并且没有C ++的多重继承所具有的所有问题。

  6. 与C#相似,D分隔结构。类是具有继承关系并从派生的引用类型Object,而结构是没有继承关系的值类型。这种分离可以是好的,也可以是坏的。它摆脱了C ++ 中的经典切片问题,并帮助将真正是值类型的类型与应该是多态的类型分开,但是起初,至少,这种区别可能会使C ++程序员感到烦恼。最终,它有很多好处,但是确实迫使您处理类型有所不同。

  7. 默认情况下,类的成员函数是多态的。您不能将它们声明为非虚拟的。由编译器决定它们是否可以(这只有在它们是final并且没有从基类覆盖函数的情况下才是实际情况)。因此,在某些情况下这可能是性能问题。但是,如果您真的不需要多态性,那么您所要做的就是使用structs,这不是问题。

  8. D有一个内置的垃圾收集器。许多来自C ++的人会认为这是一个严重的缺点,并且说实话,目前,它的实现可能会花费一些严肃的工作。它一直在改进,但是绝对不能与Java的垃圾收集器相提并论。但是,这可以通过两个因素来缓解。第一,如果您主要在堆栈上使用结构和其他数据类型,那么这不是一个大问题。如果您的程序不是经常在堆上分配和取消分配东西,那就没问题了。第二,如果愿意,可以跳过垃圾收集器,而只需使用C mallocfree。有一些语言功能(例如数组切片)),您必须避免或小心使用它们,并且某些标准库在没有至少使用GC(尤其是字符串处理)的情况下才真正无法使用,但是如果满足以下条件,则可以使用D编写而不使用垃圾收集器你真的想要 明智的做法可能是通常使用它,然后在分析表明它对性能关键代码造成问题的情况下避免使用它,但是如果您愿意,可以完全避免使用它。随着时间的流逝,GC的实现质量将得到改善,从而消除了使用GC可能引起的许多担忧。因此,最终,GC不会成为一个大问题,并且与Java不同,如果需要,您可以避免它。

可能还会有其他人,但这是我目前能想到的。而且,如果您会注意到,它们都是折衷方案。D选择做一些不同于C ++的事情,这些事情在C ++的工作方式上具有明显的优势,但也有一些缺点。哪个更好取决于您在做什么,并且在很多情况下,一开始看起来似乎只会更糟,然后一旦您习惯了就不会有问题了。如果有的话,D中的问题通常将是新问题,这是其他语言以前没有做过或没有像D那样做过的新东西引起的。总体而言,D从C ++的错误中学到了很多东西。

D作为一种语言,在C ++方面有很多改进,我认为D在客观上更好。

  1. D 有条件编译。这是我用C ++编程时经常会错过的功能之一。如果将C ++添加进去,那么在涉及模板之类的东西时,C ++将会得到长足的进步。

  2. D具有编译时反射

  3. 默认情况下,变量是线程局部的,但是shared如果您希望使用变量,可以是。这使得处理线程远远比C ++更清洁。您完全可以控制。您可以使用immutable消息传递在线程之间进行通信,也可以创建变量shared并使用互斥体和条件变量以C ++的方式进行操作。甚至通过引入sync(类似于C#和Java),也比C ++有所改进。因此,D的线程情况好于C ++。

  4. D的模板比C ++的模板功能强大得多,从而使您可以轻松得多地完成更多工作。而随着加入模板的限制,错误消息的方式比他们在C ++。D使模板非常强大且可用。D的主要合作者之一是Modern C ++ Design的作者,这绝非偶然。与D模板相比,我发现C ++模板严重不足,有时在C ++编程时可能会非常沮丧。

  5. D具有内置的合同编程

  6. D有一个内置的单元测试框架。

  7. D具有string(UTF-8),wstring(UTF-16)和dstring(UTF-32)的Unicode的内置支持。它使处理unicode变得容易。而且,如果您只想使用stringunicode,而不用担心unicode,那么您可以-尽管对unicode的基础有所了解确实对某些标准库功能有所帮助。

  8. D的运算符重载比C ++更好,允许您使用一个函数同时重载多个运算符。一个典型的例子是当您需要重载基本算术运算符,并且除运算符外,它们的实现是相同的。字符串混合器使操作变得轻而易举,使您能够为它们全部提供一个简单的函数定义。

  9. D的数组比C ++的数组好得多。它们不仅是具有长度的适当类型,而且可以附加并调整大小。连接它们很容易。最重要的是,它们有切片。这对于有效的阵列处理是一个巨大的福音。字符串是D中的字符数组,这不是问题(事实上,这很棒!),因为D的数组是如此强大。

我可以继续下去。D提供的许多改进都是小事(例如,使用this构造函数名称或禁止if语句或循环体(其中分号是它们的整体)),但是其中一些改进很大,将它们全部加在一起时,带来更好的编程体验。C ++ 0x确实添加了D所缺少的C ++的某些功能(例如auto,lambda),但是即使进行了所有改进,从客观上讲C ++作为语言还是要比D更好。

毫无疑问,有很多主观原因让彼此喜欢,并且D的实现相对不成熟有时可能会成为问题(尽管最近它一直在迅速改善-特别是自从存储库移至github以来) ,并且缺少第3方库绝对是一个问题(尽管D可以轻松调用C函数,而C ++函数在较小程度上肯定可以缓解问题)。但是这些是实现问题的质量,而不是语言本身的问题。并且随着实现问题的质量解决,使用D将变得更加令人愉快。

因此,我想这个问题的简短答案是“非常少”。D作为一种语言,通常优于C ++。


2
垃圾收集语言使用的内存比非GC语言多2-5倍(根据Alexandrescu关于YT的说法),因此如果(内存使用)成为瓶颈,那肯定是一个问题。
NoSenseEtAl 2011年

9

RAII和堆栈内存的使用

D 2.0不允许RAII出现在堆栈上,因为它删除了scope在堆栈上分配类实例时的关键字值。

您无法在D中进行值类型继承,因此,有效地迫使您对任何形式的RAII进行堆分配。
也就是说,除非你使用emplace,但是这是非常痛苦的使用,因为你必须手动分配内存。(我还没有找到emplace在D中使用的实用方法。)


6

C ++可以使您变得冗长得多。根据您喜欢推理还是冗长,这在您的眼中可能是好是坏。

比较C ++中的运行时备注

template <typename ReturnType, typename... Args>
function<ReturnType (Args...)> memoize(function<ReturnType (Args...)> func)
{
    map<tuple<Args...>, ReturnType> cache;
    return ([=](Args... args) mutable {
            tuple<Args...> t(args...);
            return cache.find(t) == cache.end()
                ? cache[t] : cache[t] = func(args...);
    });
}

与D中的相同:

auto memoize(F)(F func)
{
    alias ParameterTypeTuple!F Args;
    ReturnType!F[Tuple!Args] cache;
    return (Args args)
    {
        auto key = tuple(args);
        return key in cache ? cache[key] : (cache[key] = func(args));
    };
}

注意,例如,带有template <typename ReturnType, typename... Args>vs (F)Args...vs Argsargs...vs args等等的额外冗长。
无论好坏,C ++都比较冗长。

当然,您也可以在D中执行此操作:

template memoize(Return, Args...)
{
    Return delegate(Args) memoize(Return delegate(Args) func)
    {
        Return[Tuple!Args] cache;
        return delegate(Args args)
        {
            auto key = tuple(args);
            return key in cache ? cache[key] : (cache[key] = func(args));
        };
    }
}

并且它们看起来几乎相同,但是这将需要一个delegate,而原始对象接受了任何可调用对象。(C ++ 0x版本需要一个std::function对象,因此无论哪种方式,它的输入都更加冗长和严格……如果您喜欢冗长的话可能会很好,如果不喜欢它会很不好。)


2

我对D不太了解,但是我认识的许多C ++程序员对此非常不满意,我个人必须同意-我不喜欢D的外观,也不会更亲近D。

为了理解为什么D没有获得更多的吸引力,您需要首先了解什么吸引了人们使用C ++。一言以蔽之,首要原因是控制。当您使用C ++编程时,便可以完全控制您的程序。是否要替换标准库?您可以。是否想进行不安全的指针转换?您可以。想违反const正确性吗?您可以。是否要更换内存分配器?您可以。是否要在原始内存中复制而不考虑其类型?如果您真的想要。要继承多个实现吗?这是你的葬礼。地狱,您甚至可以获得垃圾收集库,例如Boehm收集器。然后,您会遇到诸如性能之类的问题,这些问题与控制息息相关-程序员拥有的控制权越多,他制作程序的优化就越多。

在做一些研究并与几个尝试过的人交谈时,我看到了以下几件事:

统一的类型层次结构。C ++用户很少使用继承,大多数C ++程序员更喜欢使用组合,并且只有在有充分理由的情况下,才应通过继承链接类型。对象的概念通过链接每种类型都严重违反了这一原理。另外,它违反了C ++最基本的原则之一-您仅使用所需的内容。就让程序员控制程序而言,没有选择从Object进行继承的选择以及随之而来的成本与C ++所代表的语言非常强烈地相反。

我听说过函数和委托的问题。显然,D同时具有函数委托作为运行时可调用函数类型,它们并不相同,但它们是可互换的或...?我的朋友与他们有很多问题。这绝对是C ++的降级,C ++已经降级std::function,您已经完成。

然后,您就具有兼容性。D与C ++并不特别兼容。我的意思是,没有一种语言与C ++兼容,让我们面对现实吧,除了C ++ / CLI有点作弊,但作为入门的障碍,必须提一下。

然后,还有其他一些事情。例如,只需阅读Wikipedia条目。

import std.metastrings;
pragma(msg, Format!("7! = %s", fact_7));
pragma(msg, Format!("9! = %s", fact_9));

printfgets与以前的C Standard库中的大问题一样,它是有史以来设计的最不安全的功能之一。如果在Stack Overflow上搜索它,您会发现很多与滥用有关的问题。从根本上讲,printf是对DRY的侵犯-您要在格式字符串中输入类型,然后在输入参数时再次输入。违反DRY的地方,如果您弄错了,就会发生非常糟糕的事情-例如,如果将typedef从16位整数更改为32位整数。它也不是完全可扩展的,想象一下如果每个人都发明了自己的格式说明符会发生什么。C ++的iostream可能很慢,它们对运算符的选择可能不是最大的,它们的接口可以使用工作,但是从根本上保证了它们的安全性,并且不违反DRY,并且可以轻松扩展它们。这不是可以说的printf

没有多重继承。那不是 C ++的方式。C ++程序员希望对他们的程序拥有完全的控制权,而强制执行您无法继承的语言违反了该原则。另外,它使继承(甚至更多)变得脆弱,因为如果由于要提供默认实现或某些东西而将类型从接口更改为类,突然间所有用户代码都将被破坏。那不是好事。

另一个示例是stringwstring。在C ++中,必须在它们之间进行转换已经非常痛苦,并且该库是否支持Unicode,而这个旧的C库仅使用const char*,并且必须根据所需的字符串参数类型编写同一函数的不同版本。值得注意的是,例如Windows标头具有一些非常令人讨厌的宏,以解决通常可能会干扰您自己的代码的问题。添加dstring到混音只会使情况变得更糟,因为现在必须管理三种字符串类型,而不是两种字符串类型。具有多个字符串类型将增加维护难度,并引入重复的代码来处理字符串。

斯科特·迈耶斯写道:

D是一种编程语言,旨在帮助程序员应对现代软件开发的挑战。它通过促进通过精确接口互连的模块,紧密集成的编程范例联盟,语言强制的线程隔离,模块化类型的安全性,有效的内存模型等来实现。

语言强制的线程隔离不是一个加分项。C ++程序员希望完全控制自己的程序,而强制执行某种操作的语言绝对不是医生所订购的。

我还将提到编译时字符串操作。D可以在编译时解释D代码。这不是一个加号。考虑一下C语言相对有限的预处理器所引起的巨大麻烦,所有资深C ++程序员都知道这种情况,然后想象一下此功能将被滥用的严重程度。在编译时创建D代码的能力很好,但是应该是语义的,而不是语法的。

另外,您可以期待一定的反射。D具有垃圾回收,C ++程序员会将垃圾回收与Java和C#之类的语言相关联,这些语言在哲学上与之直接相对立,并且语法上的相似性也使他们想到。这不一定客观上是合理的,但一定要注意。

从根本上讲,它没有提供C ++程序员无法做到的很多功能。用D 编写阶乘元程序也许更容易,但是我们已经可以用C ++编写阶乘元程序。也许在D中您可以编写一个编译时的光线跟踪器,但是无论如何也没有人真正想要这样做。与C ++哲学的根本违背相比,在D中可以做的事情并不是特别值得注意。

即使这些问题只是表面上的问题,但我可以肯定地说,表面上D实际上根本不像C ++的事实很可能是许多C ++程序员不迁移到D的一个很好的理由。也许D需要做一个更好的广告自己。


9
@DeadMG:这是100%不正确的,并且缺少要说的意思这绝对是C ++的降级,C ++已经降级std::function,您已经完成了。为什么?例如,因为您还有函数指针。这正是在d同样的事情:D的“功能”是函数指针,并且D“代表”是一样的C ++的std::function(除非它们是内置的)。任何地方都没有“降级”-它们之间是1:1对应的,因此,如果您熟悉C ++,就不会感到困惑。
Mehrdad

10
@马克·特拉普:我必须承认,我不太理解您在该主题上的立场–评论不用于评论答案吗?
klickverbot 2011年

6
@Mark Trapp:我的意思是,这里的大多数评论不是过时的(您链接的元讨论专门适用于已经包含在原始帖子中的建议),但是指出了该帖子中仍然存在的事实错误。 。
klickverbot 2011年

7
关于格式的注释:D的格式函数是类型安全的(解决了安全/溢出问题),并且不违反DRY,因为格式字符串仅指定应如何格式化参数,而不是参数的类型。这要归功于D的类型安全变量。因此,该反对意见至少是完全无效的。
贾斯汀W

17
@Mark:不管当前关于它们的政策是什么,我都觉得这很愚蠢,并且阻碍了评论讨论的删除。我认为这个答案进行了广泛的讨论(我现在对此很感兴趣),但是我不确定,而且我无法找出答案。您链接到的那个房间有超过1万条消息,我根本没有机会找到我似乎记得曾经进行过的讨论,但是却记不清其中的内容。有关此答案的讨论属于此问题,而不属于某个聊天室,在聊天室中,他们可能会混在一起讨论性,毒品和摇滚乐。
2011年

1

我在C ++中欣赏的一件事是能够将函数参数或返回值记录为C ++引用(而不是指针),从而暗示采用非null值。

D版:

class A { int i; }

int foo(A a) {
    return a.i; // Will crash if a is null
}

int main() {
    A bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    return foo(bar);
}

C ++版本:

class A { int i; };

int foo(A& a) {
    return a.i; // Will probably not crash since
                // C++ references are less likely
                // to be null.
}

int main() {
    A* bar = null;
    // Do something, forgetting to set bar in all
    // branches until finally ending up at:
    // Hm.. I have to dereference the bar-pointer
    // here, otherwise it wont compile.  Lets add
    // a check for null before.
    if (bar)
        return foo(*bar);
    return 0;
}

公平地说,您可以通过制作AD struct并将foo()-argument 标记为a ref(与C#类似,类是引用类型,而结构是值类型)来接近C ++ 。

我相信有一个计划创建NonNullable类的模板作为D标准库构造。即便如此,我还是喜欢与Type&相比的简洁性NonNullable(Type),并且更喜欢将non-nullable作为默认值(渲染类似Typeand Nullable(Type))。但是现在为D改变这一点为时已晚,我现在正在偏离主题。


3
D中的函数参数和返回值都可以标记为与refC ++相同的效果&。一个主要的区别是ref即使是,它也不会是暂时的const
乔纳森·M·戴维斯

我喜欢D中禁止返回对局部变量的引用的方式,直到我读完您的评论,我才意识到这一点。但是您仍然可以返回非局部null引用,而无需考虑C取消引用运算符会让您思考的方式。
lumor'8

你让事情变得混乱。类始终是引用,并且与ref分开。D中的引用类似于Java中的引用。它们是托管指针。ref传递或返回就像在C ++中通过&传递或返回。通过ref传递类引用就像在C ++中使用&传递指针(例如A *&)。类不会进入堆栈。是的,NonNullable将使得有一个可以保证为非空的类引用成为可能,但这与ref完全分开。您尝试在C ++代码中执行的操作在D中不起作用,因为类不在堆栈中。结构做。
乔纳森·M·戴维斯

1
所以是的,能够有一个非nullull的类引用会很好,但是C ++设法完成了您要显示的操作,因为它允许将类放在堆栈中并允许将指针取消引用。虽然可以在D中取消引用指针,但类是引用,而不是指针,因此您不能取消引用它们。由于您不能将它们放在堆栈上,也不能取消引用它们,因此D内置没有任何方法可以拥有不能为null的类。这一种损失,但是NonNullable可以解决它,并且从结构和类的分离中获得的收益通常都更大。
乔纳森·M·戴维斯

2
按照语言标准,C ++引用不能为空(说“可能不会为空”是不正确的,因为它不能为空)。我确实希望有一种方法可以禁止null作为类的有效值。
jsternberg 2011年

1

C ++比D做得更好的最重要的事情是与旧版库的接口。各种3D引擎,OpenCL等。由于D是新的,因此可以选择的库数量要少得多。

C ++和D之间的另一个重要区别是C ++拥有多个财务上独立的供应商,但截至2014年,D实际上只有一个由2人组成的团队来创建它。有趣的是,“第二资源原则”说项目永远不应该依赖于只有一个供应商的技术,组件,甚至对于软件来说也是如此。

为了进行比较,Ruby解释器的第一个版本是由Ruby的发明者Yukihiro Matsumoto编写的,但是2014时代的主流Ruby解释器实际上是由其他人从头开始编写的。因此,Ruby可以被视为一种拥有多个财务独立供应商的语言。另一方面,D可能是一项了不起的技术,但它取决于开发该技术的少数开发人员。

Java的历史表明,即使一种技术(在这种情况下为Java)具有优良但单一的财务状况,也存在很大的风险,即无论庞大的公司用户群如何,该技术实际上都被丢弃了。引用了Apache Software Foundation,其中EC代表“执行委员会”:

Oracle向EC提供了Java SE 7规范请求和许可证,这些请求和许可证是自相矛盾的,严格限制了规范的独立实现的分发,最重要的是,禁止分发规范的独立开源实现。

作为历史记录,可以说Java小程序在HTML5 WebGL开发之前已有硬件加速了3D画布。如果Java是社区项目,则可以解决Java applet的启动速度问题,但是Java的唯一资助者Sun Microsystems的高管认为修复Java实现的重要性不那么重要。最终结果:多个供应商提供的HTML5画布作为Java GUI框架(Swing等)的“穷人复制品”。有趣的是,在服务器端,Python编程语言具有Java承诺的相同优势:只要不将Python应用程序编译为机器代码,编写一次,即可在每台服务器上运行,而无需考虑硬件。Python与Java一样古老/年轻,但是与Java不同,它是

摘要:

在评估用于生产的技术时,技术的最重要属性是人员,开发人员,社会过程,开发发生的地方以及财务上独立的开发团队的数量。

使用技术T1优于技术T2是否更有利,取决于技术的供应商,以及技术T1是否比T2更便宜地解决与项目相关的问题。例如,如果忽略了单个供应商问题,那么对于信息系统而言,Java将是比C ++更好的技术,因为Java二进制文件在部署到新硬件时不需要重新编译,并且无需进行与内存管理相关的软件开发工作Java比C ++小。从头开始开发的项目(例如,不依赖于其他库的项目)在D中进行开发可能比C ++便宜,但另一方面,C ++有多个供应商,因此从长远来看风险较小。(在Java示例中,Sun Microsystems几乎可以运行,

某些C ++局限性的可能解决方法

解决C ++某些局限性的一种可能的解决方法是使用一种设计模式,在该模式中,将初始任务分解成各个部分,然后将各个部分“分类”(分类,聚类,划分,其他字词对- 2类:与控制逻辑相关的任务,其中内存访问模式不允许局部性;类似信号处理的任务,可以轻松实现本地化。信号处理“类似”任务可以实现为一组相对简单的控制台程序。与控制逻辑相关的任务全部放置在一个用Ruby或Python或其他方式编写的脚本中,其中软件开发的舒适性优先于速度。

为了避免昂贵的操作系统进程初始化和操作系统进程之间的数据复制,小型C ++控制台应用程序集可以实现为单个C ++程序,该程序由Ruby / Python / etc作为“ servlet”启动。脚本。Ruby / Python / etc。脚本在退出前关闭servlet。“ servlet”与Ruby / Python / etc之间的通信。脚本在Linux命名管道或类似机制上进行。

如果初始任务不能轻易地划分为可以分为上述两个类别的部分,那么可以尝试重新措辞该问题,以便改变初始任务。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.