繁体   English   中英

简单的C ++函数 - 这段代码“好”吗?

[英]Simple C++ function — Is this code “good”?

以下代码由为我的小组工作的顾问制作。 我不是一个C ++开发人员(虽然工作在很多语言中)但是想对以下代码有一些独立的意见。 这是在Visual Studio C ++ 6.0中。 我有一个直觉反应(显然不是一个很好的反应),但我想要那些来自经验丰富(甚至不是那么没有经验)的C ++开发人员的“直觉反应”。 提前致谢!

// Example call
strColHeader = insert_escape(strColHeader, ',', '\\'); //Get rid of the commas and make it an escape character

...略...

CString insert_escape ( CString originalString, char charFind, char charInsert ) {
    bool continueLoop = true;   
    int currentInd   = 0;

    do {
        int occurenceInd = originalString.Find(charFind, currentInd);

        if(occurenceInd>0) {
            originalString.Insert(occurenceInd, charInsert);
            currentInd = occurenceInd + 2; 
        }
        else {
            continueLoop = false;   
        }
    } while(continueLoop);
    return(originalString);
}

哼。 我认为

CString strColHeader;
strColHeader.Replace(",", "\\,") 

也会这样做。

我不喜欢代码,我倾向于从while循环中断,而不是有一个不必要的bool'continin'标志。 当他可以使用while (occurenceInd != 0)作为他的循环控制变量而不是布尔值时,这会加倍。

增加计数器也依赖于“+2”,这似乎不能立即理解(不是一瞥),最后(最重要的)他似乎没有做评论。

中间有一个一个一个错误的错误:看看如果第一个字符是逗号会发生什么:“,abc,def,ghi”:我假设所需的输出是“\\, abc \\,def \\,ghi“,而是你得到原来的字符串:

int occurenceInd = originalString.Find(charFind, currentInd);

OccurrenceInd返回0,因为它在第一个字符处找到了charFind。

if(occurenceInd>0) 

0不大于0,所以取else分支并返回原始字符串。 CString :: Find在找不到内容时返回-1,所以至少比较应该是:

if(occurrenceInd >= 0)

最好的方法是使用Replace函数,但如果你想手动完成,更好的实现可能看起来像这样:

CString insert_escape ( const CString &originalString, char charFind, char charInsert ) {
    std::string escaped;
    // Reserve enough space for each character to be escaped
    escaped.reserve(originalString.GetLength() * 2); 
    for (int iOriginal = 0; iOriginal < originalString.GetLength(); ++iOriginal) {
        if (originalString[iOriginal] == charFind)
            escaped += charInsert;
        escaped += originalString[iOriginal];
    }
    return CString(escaped.c_str());
}

已经提到了错误。 但是,他们认为任何人都可能遇到的问题很快就会被快速破解,而且还没有经过适当的测试,特别是如果他们不熟悉CString的话。

我更担心风格的东西,因为他们建议有人不熟悉C ++。 使用bool continueLoop只是简单的C ++。 它代表函数代码的三分之一,可以通过使用简单的if ... break构造来消除,使代码更容易在流程中遵循。

此外,变量名称“originalString”非常具有误导性。 因为它们是按值传递的,所以它不是原始字符串,而是它的副本! 然后他们无论如何都要修改字符串,因此它不再是与原始文本相同的对象或相同的文本字符串。 这种双重谎言暗示了混乱的思维模式。

CString有一个Replace()方法......(这是我的第一反应)

我看到了很多不好的代码,而且比这更糟糕。 但是,如果没有明显的理由,那么就不要使用内置功能。

我的直觉反应是: WTF 最初是如何格式化代码(有许多我不喜欢格式化的东西),然后通过检查代码实际在做什么。

这个开发人员对C ++中对象复制的理解存在严重问题。 这个例子本身就是一个WTF(如果该函数的开发人员真的使用了他/她自己的函数):

// Example call
strColHeader = insert_escape(strColHeader, ',', '\\'); //Get rid of the commas and make it an escape character

CString insert_escape ( CString originalString, char charFind, char charInsert )
  1. strColHeader副本作为originalString传递(注意没有&
  2. 该功能修改了此副本(精)
  3. 该函数返回副本的副本,该副本又替换原始的strColHeader 编译器可能会将其优化为单个副本,但仍然像这样传递对象副本对C ++不起作用。 人们应该知道参考文献。

一个经验丰富的开发人员会将此功能设计为:

void insert_escape(CString &originalString, char charFind, char charInsert)

要么:

CString insert_escape(const CString &originalString, char charFind, char charInsert)

(可能会将参数命名有点不同)

正如许多人所指出的那样,开发人员可以做的理智是检查API文档以查看CString已经有一个Replace方法......

如果你想要评估这个开发人员的C ++技能水平,我会说这证明了中级的低端。

代码完成了工作,并且不包含任何明显的“咆哮者”,但正如其他人所写,有更好的方法来做到这一点。

我不会提供替代代码,因为它只会添加到已提供的代码中。

但是,我的直觉是代码有问题。

为了证明这一点,我将列举原始函数中的一些要点,表明它的开发人员不是一位经验丰富的C ++开发人员,如果你需要一个干净的实现,你应该调查一下:

  • copy :参数作为副本而不是const-reference传递。 在考虑对象时,这在C ++中是一个很大的NO NO。
  • 错误我想有一个错误,在“如果(occurenceInd> 0)”的一部分。 通过在MSDN上读取CString的文档,CString :: Find方法返回-1,而在查找失败时不返回0。 这段代码告诉我,如果逗号是第一个字符,它将不会被转义,这可能不是函数的重点
  • 不需要的变量不需要 “continueLoop”。 将代码“continueLoop = false”替换为“continue”,将“while(continueLoop)”替换为“while(true)”就足够了。 请注意,继续这种推理使编码器能够更改内部功能(在一段时间内替换do ...
  • 更改返回类型 :可能会选择细节,但我会提供一个替代函数,它不会返回结果字符串,而是接受作为引用(返回时少一个副本),原始函数被内联并调用替代。
  • 在可能的情况下再次添加const ,选择详细信息:两个“char”参数应该是const,如果只是为了避免意外修改它们。
  • 可能的多重新分配该函数依赖于CString数据的潜在多次重新分配。 Josh使用std :: string保留的解决方案是一个很好的解决方案。
  • 使用完全CString API :但与Josh不同,因为你似乎使用CString,我会避免使用std :: string并使用CString :: GetBufferSetLength和CString :: ReleaseBuffer,这使我能够拥有相同的代码,少一个对象分配。
  • 神秘的插入法? 这是我,或者没有CString :: Insert ??? (见http://msdn.microsoft.com/en-us/library/aa252634(VS.60).aspx )。 事实上,我甚至未能在Visual C ++ 2008和2005的MSDN中找到CString ......这可能是因为我应该真的去睡觉了,但是,我觉得这值得研究

该顾问是否由代码行支付? 有几个人指出CString类已经提供了这个功能,所以即使你不是程序员,你知道:

  • 该功能是不必要的。 它增加了程序的复杂性,大小和可能的执行时间。
  • CString函数可能有效并且可能有效; 这可能是也可能不是。
  • CString函数已记录,因此是可支持的。
  • 顾问要么不熟悉标准的CString函数,要么认为他/她可以通过编写新函数做得更好。
    • 有人可能会得出结论,顾问不熟悉其他标准功能和最佳实践。
    • 选择为基本功能编写新代码而不考虑可能存在标准版本是一种公认​​的不良做法。

也许是最重要的,最红的标志:你的直觉促使你从StackOverflow社区获得意见。

相信你的直觉。

看起来没问题,如果有点,我不知道,黑客。 最好使用该库,但我不会去重写这个例程。

这是在Visual Studio C ++ 6.0中。

肠道反应: 发痒 认真! VC ++ 6附带的C ++编译器已知存在问题,并且通常表现非常糟糕且已有10年历史。

@Downvoters:考虑一下! 我非常认真地说这个。 VC6只是相对无效的, 不应该再使用了 特别是自微软停止支持该软件以来。 有些情况下这是无法避免的,但很少见。 在大多数情况下,代码库的升级可以节省资金。 VC ++ 6只是不允许利用C ++的潜力,这使得客观上较差的工具。

看起来人们已经为你解决了这段代码的一些功能方面,但是我建议你不要像你在这里使用的那样改变命名。

除了UI控件之外,通常不赞成使用匈牙利表示法。 这对数字更重要......例如:

我宣布:

float fMyNumber = 0.00;

然后我在整个应用程序中使用它。 但后来,我将其改为双,因为我意识到我需要更高的精度。 我现在有:

double fMyNumber = 0.00;

确实,大多数优秀的重构工具都可以为您解决这个问题,但最好不要附加这些前缀。 它们在某些语言中比其他语言更常见,但从一般的风格角度来看,你应该尽量避免使用它们。 除非你使用记事本,否则你可能有类似于Intellisense的东西,所以你真的不需要查看变量名来确定它是什么类型。

总是有更好的实施。 如果您使用该功能作为顾问不是很好的示例,您可能还需要考虑,虽然他们不知道已经存在的功能,但他们可能有项目构建的经验和理解。

软件开发不仅仅是完美的功能,还包括整个架构的结构。

当我看到一个do ... while循环时,我总是担心; IMO他们总是很难理解。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM