c语言 二叉树创建二级指针字符串,为什么二叉树的建立的函数参数用二级指针,而遍历只用一级指针?...

该楼层疑似违规已被系统折叠 隐藏此楼查看此楼

github.com/FrankHB/pl-docs/blob/master/zh-CN/why-is-pointer-awful.md

八成因为你看的是垃圾代码(即便这是你在教材上看到的主流写法,实际也会避免)。

首先可以给出一个比较普遍(不限定具体语言和用例)但较弱的解释。

这种用法中,使用指针表示所谓的“传出参数”(output parameter) ,保证函数体内的修改会影响主调函数(caller) 所在的外部词法环境(lexical environment) ,作为对缺乏按引用传递参数的变通。这是在C语言中常用的惯用法,而在C++中通常是不必要的,因为C++中直接就有引用类型来应对这种情况。

从程序语言设计的角度讲,使用指针模拟引用参数能简化语言规则,但这里模拟的不到位。最显然地,传引用是不可能有空指针的,而使用指针无法在类型上表达不可空的契约(nonnullable contract) ,因此接口的使用者需要额外的不由类型检查保证的约束。就传出参数的例子讲,使用这个参数的接口的实现(函数体)中应对非预期的空指针就会出问题:是检查呢,还是不检查呢?如果检查,那么接口就具有所谓的wide contract,是一种恶劣的设计(详细暂时不展开);如果不检查,那么凭空多出额外文档约定或者误用出错的成本。这个问题的根本原因是不可空的契约是原始含义,而指针类型不恰当地表示了定义域泛化(允许空值)后的值,是不恰当的类型使用方式,程序的语义和预期接口的语义匹配得明显不够精确。对C这种类型系统功能差强人意的语言,使用附加文档几乎是唯一现实的变通;而使用C++的引用这样的专用类型就没这个问题。在直接有更明显符合原意、可读性更好、更不容易出错的选项下,还要使用抽象能力较差的手法,这至少体现了接口设计者对语言特性缺乏了解。

然后是稍微具体的解释。

为什么使用传出参数?其实完全不必要。传出参数的直接作用是扩散副作用(side effect) ,包括影响到主调函数状态的对象修改操作。而在正常的代码中,这种散播修改的操作是不必要的,几乎总是可以使用返回值和赋值组合解决。不受到具体控制流限制的传出操作本身在工程上经常难以控制容易被滥用,因为补充文档约束基本是得靠人自觉的,不会有语言实现帮你盯着;因此几乎就是烂接口设计的标志。

当然反例也是有的,一是参数本身会影响函数签名而导致修改返回类型会引起其它不便,二是ABI兼容。不过,这两种反例经常被滥用(过度依赖ABI兼容这种历史包袱是在类型选取以外也流毒无穷的更普遍的滥用)。

另外,担心返回值复制开销过大在C++这样的语言中普遍是多余的,因为就语言规则(特别是复制消除)来讲并没有这种必须低性能的限制,真发现慢了可以说都是实现质量(QoI) 问题;退一万步讲,即便在主流实现中真慢了(往往是实现迁就ABI兼容的缘故,像Itanium ABI对unique_ptr和指针参数传递是否允许使用寄存器的区别对待),影响又恰好被发现了,也是需要做性能测试和剖析的才能确定的结果。

此外,注意引用不是对象类型(抽象机语义下必须占用空间),而显式约定未指定占用空间的,因此有更大优化余地;即便实际不内联的调用传递参数时主流实现都使用指针兼容的二进制方式,但这在脱离具体ABI约定时没有保证。代替引用反而因为更固定的ABI限制而更难以优化。这根本上也是由于不匹配精确语义(包括“不依赖占用空间”之类的抽象性质)的结果。

第三是就这种建立数据结构的用例的具体解释。

这种惯用法?一个字:烂。

对模块化的接口设计来讲,参数就是应该表示逻辑上的输入,而不是输出(上面说了,用传出参数是不得已的变通,在C++中没有必要)。这种建立数据结构的代码,逻辑上的输入就是调整数据结构性质的参数(完全可以没有),而输出就是建立好的数据类型的实例——通常在C++直接就是某种类类型的数据类型的值。既然不是数组也不是函数类型(作为返回类型会退化为指针——又是个继承自C的烂特性),返回复制初始化能被消除,为什么不通过返回值而非得用传出参数?明显没事找事。

最后,所谓什么栈什么内存的都是耍流氓。

实现上面的语义精确性,对用户来讲容易遵循的更普遍的一般形式是最小依赖原则,也就是说根本不需要用底层实现的特例形式来解释的东西就完全不必要。像栈分配多少大小给参数,撑死也就是指针传递实现按引用传递参数的一类ABI的描述,这种以偏概全的手法连C++的抽象都表达不出来,尤其有害的是容易对举一反三不习惯的新手构成误导。而就抽象而言,C++这里显然还嫩呢……

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值