C程序员开始编写C++有什么坏习惯?

Did*_*set 34 c c++

最近的一次讨论结束时嘲笑程序员的坏习惯,当他们开始用另一种语言编程时,他们过于暴露于某种语言.最好的例子是Pascal程序员开始#define begin {#define end }开始写C.

目标是在他们开始使用C++时尝试捕捉C程序员的坏习惯.

告诉你不要遇到的大事.请回答一个建议,试图实现一种最好的.

对于那些对良好习惯感兴趣的人,请看一下这个问题的接受答案.

Phi*_*ipp 51

使用原始指针和资源而不是RAII对象.

  • 阿门.正因为什么当他们抱怨C++中的内存管理时我会看到有趣的人 - 如果他们遵循这个简单的事情,内存管理就不是问题了. (7认同)
  • @Thanatos C++ 0x标准给我们带来了std :: shared_ptr,所以是的,内存管理现在更清洁了.但是仍然必须避免循环引用,因此必须在共享指针和弱指针之间做出决定.我认为将内存管理声明为非问题是很冒昧的. (4认同)
  • @Stephane Rolland:也许 - 但也许RAII的另一个好处超过了(罕见)案例:RAII负责资源管理,并且不仅可以自动处理内存,还可以自动处理锁,文件句柄,套接字,数据库连接等.程序员不得不做额外的工作.大多数其他使用垃圾收集的语言都需要程序员手动释放(Python的"with",C#"使用"等)大多数其他资源. (3认同)
  • @RCIX:这就是重点:`using`*是*免费手动 - 不是内存,而是普通资源.每当我"打开"一个必须"关闭"的资源(任何实现`IDisposable`的东西)时,我必须用`using`来包装它 - 我必须*记住*来编写将手动关闭或释放资源的代码,因此,资源分配和解除分配的负担仍然在我身上.如果我忘了,我已经泄漏了资源,至少在GC得到它之前,这可能为时已晚.`using`只是'free`的语法糖,但它仍然是免费的. (2认同)

Fra*_*eld 38

  • 使用char*而不是std :: string
  • 使用数组代替std :: vector(或其他容器)
  • 在适当的地方不使用其他STL算法或库
  • 滥用预处理器,其中constants,typedef或templates会更好
  • 编写SESE样式(单入口单出口)代码

  • 为什么这些问题总是包含*"每个答案一个建议,请"*有人总是创建一个列表? (23认同)
  • @Matt Joiner string #length()在O(1)中执行,strlen()在O(n)中执行 - 对字符串的几乎所有操作都必须检查其长度.堆栈上的第二个数组比std :: vector快,它甚至支持直接访问分配的内存. (10认同)
  • @Matt:是的,重写工作代码是愚蠢的,但这不是这个问题的内容.*继续*使用原始数组是一个坏习惯. (7认同)
  • @Matt Joiner.AFAIK std :: vector的实现只是封装了一个C数组.我没有检查过...但是AFAIK使用std :: vector而不是C-array的成本接近于NULL.尽管如此,我可以理解你,C-traditionnalist可能会害怕学习新奇并遵守STL的严谨性. (5认同)
  • char*和数组非常可靠.并且快了很多.EW.SESE还有什么问题?(它甚至不是C的东西?) (3认同)
  • 如果你想要的只是速度,那就去装配吧.0端接的字符串和没有范围检查的数组不是"可靠的",它们是一堆陷阱.而SESE简直是丑陋而毫无意义.但是,SESE不是C事. (3认同)
  • @Matt Joiner:禁用例外?这会导致使用异常的代码出现各种问题,特别是STL.我认为这些模式通常会使代码异常安全.例如RAII,并且在*可能失败的调用之后"提交"更改*.即使没有例外,我更喜欢RAII和早期退货(警卫)而不是手动清理和SESE. (3认同)
  • 我想传达的是,在C++主义方面,没有必要挥舞宗教旗帜.用C++改写现有的每个C app都不会让世界变得更美好.也不会修复bug从天空掉落:).一切都有时间和地点,幸运的是C++通常会让你选择. (2认同)
  • @Matt:那么,'malloc`究竟做了什么呢?还有什么额外的'指针deref'你在说什么? (2认同)

jef*_*ffm 30

声明函数顶部的所有变量,而不是尽可能接近它们的使用位置.

  • 想象一下,一次读取一行文件的循环.您创建一个循环,通过cin读取字符串,然后以某种方式处理它.如果你声明字符串变量"尽可能接近它所使用的位置",它在循环内部,它将减慢你的程序,因为它将在循环中每次迭代时调用字符串的构造函数.如果在函数顶部声明字符串变量,它只会调用一次构造函数,并且速度会更快. (4认同)
  • @fish ......"尽可能接近",但不要靠近! (2认同)

Bin*_*ier 19

不使用STL,特别是std :: string,

和/或

使用std :: strings并在紧凑的角落恢复旧的c字符串函数.

  • @Stephen:STL(或者你想要称之为)不是*事实上的标准,而是一个de juris标准:) (5认同)
  • 许多月前,在进行单元测试之前,我给了一位经验丰富的承包商一个*相当*微不足道的字符串处理任务.他检查了200多行字符串代码,旧式c处理.当我用12行左右的STL代码替换它时,他感到很恼火."但它奏效了!" 他说."是的,但是我重复使用经过验证的代码,可维护**并且它也可以工作**",我说,并鼓励他阅读STL,因为他的C++经验中有90%来自MFC和COM - 他从未使用过(这是他的借口). (4认同)

C J*_*son 18

  1. 编写2000行代码的类定义.
  2. 将该类定义复制并粘贴到12个不同的位置.
  3. 在简单的虚拟方法执行时使用switch语句.
  4. 无法在构造函数中分配内存并在析构函数中释放.
  5. 采用可选参数的虚方法.
  6. 编写while循环来操作char*字符串.
  7. 写巨型宏是一个页面的长度.(本来可以使用模板).


Jen*_*edt 17

使用指针而不是引用

  • 所以更好的是:不遵守规则,"尽可能使用引用,必要时使用引用". (3认同)
  • 不可能有std容器的引用,因此指针的使用仍然是标准C++核心的一部分. (2认同)

Jar*_*Par 17

usings 添加到头文件中,以便它们可以避免std::string类型声明中的名称.


Mat*_*_JD 14

非常有经验的开发人员不理解编译甚至面向对象的编程

我开始帮助一个项目,其中一个高级人员遇到了一些过去工作但现在没有的代码问题.

(类名已被更改以保护无辜,我不记得确切的名称)他有一些C++代码正在侦听传入的消息类并阅读它们.它过去的工作方式是传递一个Message类,然后他会在其上插入一个变量,以找出它是什么类型的消息.然后,他将C-style转换为另一个他写的继承自Message的专门类.这个新类具有可以提取数据的功能.现在,这对他来说很好,但现在却没有.

经过几个小时查看他的代码,他看不出问题,我看了看他的肩膀.我马上告诉他,将C风格的消息传递给派生类并不是一个好主意.他不同意我的观点并说他多年来一直这样做,如果这是错的,那么他所做的一切都是错的,因为他经常使用这种方法.他得到了承包商的进一步支持,他告诉我我错了.他们都认为这总是有效并且代码没有改变所以它不是这种方法,而是其他破坏了他的代码的东西.

我看得更远,发现了差异.Message类的最新版本具有虚函数,之前没有使用虚拟.我告诉他们这对他们现在有一个虚拟的桌子和正在查找的功能等等......这导致他们的问题等等......他们最终同意了,我被提出了一个评论我永远不会忘记:"虚拟完全搞砸了多态性和面向对象的编程".

我向他们转发了一个装饰器模式的副本,作为如何向现有类添加一个函数但是没有从它们那里听到回复的示例.他们如何解决我不知道的想法.

  • "Virtual完全搞砸了多态性和面向对象的编程." - 什么!我也永远不会忘记这一点. (3认同)
  • 那些程序员应该被解雇了. (2认同)

Nem*_*vic 13

一个词:宏.我不是说宏没有地方都在C++中,但前者C程序员往往太多之后便切换到C++使用它们.


Mik*_*our 10

使用C风格的演员表.

C++允许您独立选择是否允许不相关类型之间的转换,以及是否允许更改constvolatile限定符,与C相比,对编译时类型安全性有相当大的改进.它还以运行时检查为代价提供完全安全的转换.

C风格的强制转型,几乎任何类型之间的未经检查的转换,允许整个类错误,可以通过更严格的强制转换来轻松识别.如果您想要审核错误转换的错误代码,他们的语法也会使它们很难搜索.


Mat*_*ner 8

假设程序员已经犯了试图学习C++的错误:

误区

  • 不使用STL.
  • 试图在课堂上包装所有内容.
  • 尝试使用模板来处理所有事情.
  • 不使用Boost.(我知道Boost可以是一个真正的PITA,也是一个学习曲线,但C++只是没有它的C + .Boost给C++一些电池).
  • 不使用智能指针.
  • 不使用RAII.
  • 过度使用例外.

争论的

  • 转向C++.不要这样做.
  • 尝试将C stdio转换为iostreams.Iostreams SUX.不要使用它.它天生就是破碎的.你看这里.
  • 使用libstdc ++库的以下部分:
    • 字符串(除了为我释放它们,去地狱之外)
    • 本地化(这与c ++有什么关系,更糟糕的是,它很可怕)
    • 输入/输出(64位文件偏移?听说过吗?)
  • 天真地相信你仍然可以在命令行上调试.如果没有代码起重机(IDE),请不要大量使用C++.
  • 关注C++博客.C++博客关于什么本质上归结为元数据和糖.除了一个很好的常见问题和经验,我还没有看到一个有用的C++博客.(请注意,这是一个挑战:我喜欢阅读一篇优秀的C++博客.)

  • IOStreams包含C库缺少的一个重要特性:可扩展性.哦,内置式安全. (6认同)
  • 麻烦是stdio也很糟糕 (4认同)
  • 关于C++ iostream的重要一点是它们完全打破了i18n/l10n的角度.当你的消息是<< broken << up << like << this时,你没有完整的句子用本地化副本替代.如果另一种语言使用不同的单词顺序或复数形式(即几乎所有单词),你就会被搞砸了.printf,OTOH,允许您将数字占位符放入格式字符串中,这样您就可以为不同的语言重新排序. (4认同)
  • 哈哈thx.我真的很喜欢C++,因为其他一切都更糟糕.但是挥舞旗帜和吟唱是没有借口的. (2认同)
  • "可移植性注意:扩展printf模板字符串语法的能力是GNU扩展.ISO标准C没有类似的东西." (2认同)

Gun*_*nar 8

写作,using namespace std因为每个人都做,然后从不反思它的意义.或者知道它意味着什么,但说" std::cout << "Hello World" << std::endl;看起来很难看".


Chr*_*ris 8

使用指针而不是引用传递对象.是的,有时您需要使用C++中的指针,但引用更安全,因此您应该尽可能使用它们.


zoo*_*opa 7

让一切都在公共场合.因此,应该是私有的数据成员不是.

  • 当他们把所有东西都公之于众时,他们就是来自C.当他们根据习惯为每个变量编写getter和setter时,他们来自Java ...... (3认同)

cel*_*vek 5

不完全理解指针和引用的语义以及何时使用其中一个或另一个.与指针相关的还有不能正确管理动态分配内存或无法使用"更智能"构造(例如智能指针)的问题.