cplusplus.com提供的错误、误解或不良建议是什么?

221

有几个关于C++标准库的参考资料,其中包括宝贵的ISO标准、MSDNIBMcppreferencecplusplus。个人而言,在编写C++代码时需要一份具有快速随机访问、短加载时间和使用示例的参考文档,我发现cplusplus.com非常有用。然而,我在这里经常听到对该网站的负面意见,因此我想得到具体答案:

cplusplus.com存在哪些错误、误解或不良建议?使用它做编码决策存在什么风险?

我希望能够通过准确引用标准来回答SO上的问题,因此我想发布可立即使用的链接,如果不是因为这个问题,cplusplus.com将是我的首选网站。


71
为什么会有负评?这是一个完全有效的问题。如果你需要参考资料,你需要一个可信赖的来源。我也听说过对cplusplus.com的抱怨,虽然我可以在那里快速获得标准库的参考,但这很有趣。 - Xeo
51
@Olafur: 我不要意见,我需要具体列出该网站上的错误。如果没有错误,我希望能够使用这个问题来消除未来的批评。 - Kerrek SB
4
@Ólafur Waage:也许。但是,有关该网站内容的准确性/真实性可以提出完全客观的观点。 - Daniel Sloof
14
我们已经在Google上的"Cplusplus.com"搜索中排名第一页。令人印象深刻的是,SO的问题很快就能爬到搜索排名前面。 - Lightness Races in Orbit
5
考虑到这个问题在“cplusplus”搜索中排名很高,我认为公平的提醒一下,自从这个问题被提出以来,cplusplus.com 已经做出了一些修正。事实上,指出错误的前三个答案现在已经不再正确。 - Mark H
显示剩余18条评论
6个回答

77

编辑: 自从本回答撰写之后,std::remove的文档已经修复。对于list::remove也适用。

让我通过一个示例来说明cpluscplus.com可能会出错的情况。

考虑来自<algorithm>std::remove函数。

事实是,std::remove不会从容器中删除项。这是因为std::remove仅使用一对迭代器工作,并且不知道实际包含项的容器。实际上,std::remove无法了解底层容器,因为它无法从一对迭代器获得关于迭代器所属的容器的信息。因此,std::remove实际上并未删除任何项,仅仅因为它无法删除。实际上从容器中真正删除项的唯一方法是在该容器上调用成员函数。

因此,如果要删除项,则使用“Erase-Remove Idiom”

 v.erase(std::remove(v.begin(), v.end(), 10), v.end()); 

但是cplusplus.com给出了错误的std::remove信息。它说

注意,这个函数不会改变新结尾后面的元素,这些元素保持其旧值仍然可访问

这不正确。范围内迭代器[new_end,old_end)仍然可解引用,但这并不意味着它们保持旧值和仍然可访问。它们是未指定的。


同样地,cplusplus.com也提供了关于list::remove错误信息。它说,

请注意,存在一个全局算法函数,remove,具有类似的行为,但在两个迭代器之间操作。

这是完全错误的。全局的removestd::removelist::remove不同,因为前者实际上并没有从容器中删除项,因为它不能,而后者(成员函数)确实删除了项,因为它可以。

这个回答是从我在以下话题中的另一个答案中复制来的,稍微修改一下:

注意:由于我最近在回复上述话题时遇到了这个问题,我记得它。在过去的两年中,我遇到了许多错误,我不记得了。如果我再次遇到,我可能会添加几个。


1
+1:这个网站上还有很多这样的错误陈述吗? - Klaim
4
@Alexander说:list::remove会从容器中移除元素。但是std::remove不会从容器中移除元素。我不能说它们的行为是“相似的”。 - Nawaz
3
好得很!那是我正在寻找的事物的非常好的例子。 - Kerrek SB
3
“相似”是有争议的,因为两个不同的操作是否相似是一个主观看法。而且,是否应该将意见伪装成文档在cplusplus.com上也是有争议的。但无论如何,“保留其旧值”是一个不可原谅的错误,它只是表明cplusplus的描述并非基于标准。 - Steve Jessop
5
@Steve:你说“相似”这个词是有争议的。如果“相似”这个词有争议,那么这很明显说明这个词不是正确的词语,在解释std::remove和list::remove的行为时应该避免使用它,因为一个解释应该尽可能地清晰明了,不应该需要另一个解释。 - Nawaz
显示剩余6条评论

42

我稍微持反对意见。cplusplus.com上有很多好的信息,仔细研究它,当然它也有问题,但是哪个网站没有问题呢?当然不包括 这个网站。这里也有很多错误信息。有些被接受的答案是完全错误的,有些被踩(甚至是负分)的答案却是正确的。

cplusplus.com的一个问题是它是一个封闭的网站;大多数其他参考网站也是如此。这与像Stack Overflow这样由社区开发的网站背道而驰。获得进行可信编辑的能力并不需要太长时间,即使是最新的新手也可以轻松提出改进建议。相比之下,cplusplus.com要求你必须在他们的工作人员中才能成为永久新手。即使你是WG21的关键成员,如果你在该网站的某个地方看到了一个bug,你也必须通过他们的电子邮件报告机制。这是讨厌的!

一个解决方案是我们在这个网站上开发自己的C++参考。这需要相当多的工作。我们必须小心谨慎,不要太学究 / 太技术性;显然,cplusplus.com雇用了至少几位技术编辑,他们使学究们保持平衡。我们必须保持信息的良好组织;这里的常见问题解答并没有很好的组织。我们也必须非常小心,不要直接从标准中借鉴过多的内容;那是违法的。


9
我曾经常逛旧的cppreference.com网站,但现在他们把它改成了像维基百科那样的东西(是否对所有人开放编辑?)...而且我不再喜欢它了。我发现很难看到重要的信息。它缺乏我从cplusplus.com获得的即时满足感,我想。 - Kerrek SB
20
哇!我看到了完全相反的情况。我不再经常访问旧版cppreference.com,因为我发现它难以遍历且写得很差。新的cppreference.com似乎是一个无广告、基于社区的网站,正是我在上一段中建议的做法。 - David Hammen
1
也许只是我自己的问题,我应该再试一次。我想查找一些<thread><atomic>的东西,但只看到了“请编写此页面”,所以我放弃了。让我再检查一下!哦,当然,C++0x支持将是一个巨大的加分项! - Kerrek SB
14
在这里发表言论的人应该注意自己的行为,不要在没有把握的情况下妄加评论。SO并不像http://www.cplusplus.com/reference/一样声称是C++库的参考资料,当用户在这里做出声明时,他们会引用规范来支持自己的观点,如果他们没有这样做,其他人就会来填补此空缺。如果某些观点是错误的,你可以看到他们的推断过程。然而,如果cplusplus.com中的信息是错误的,你可能会写出在除作者所用的C++实现之外的某些C++实现上无法运行的代码。问题在于cplusplus.com的风格比较随意,但它又试图让自己看起来很正式。 - Steve Jessop
4
SO 是非正式的,旨在看起来非正式。如果 cplusplus.com 不打算作为准确的文档/参考资料,而我错过了免责声明,那么可以理解为将任何石头扔给那些以此方式使用它的人而不是网站本身。但重点是,仅仅因为 cplusplus.com 关于 C++ 函数的某些说法并不意味着它是正确的,如果你打算将其用作快速参考,则值得知道这一点。我使用它来查找函数签名,但从不用它来确定我的代码是否符合标准。 - Steve Jessop

16

http://www.cplusplus.com/reference/clibrary/cstring/strncpy/

此处未提到:“如果复制发生在重叠的对象之间,则行为是未定义的。”(C89标准中的4.11.2.4。我手头没有C90的副本,这就是C ++ 03实际上所涉及的内容,但它们应该仅有像页码之类的差异。)


啊,老旧的C库...不错。 - Kerrek SB
7
他们提到“目标和源不得重叠”。 - Sniper
2
@Sniper,“不得重叠”并不等同于“行为未定义”。你的评论实际上揭示了cplusplus.com一个微妙而普遍的缺陷——它听起来很正确,但却是不正确的。 - Andrew Henle
@Sniper:我想可能在2011年回答这个问题时它没有这么说。我会将“不得重叠”视为输入的充分约束条件。 - Steve Jessop
2
@AndrewHenle 实际上,使用“shall not”一词表示未定义行为非常普遍。事实上,C标准本身也是如此。参见链接。抱歉我手头没有实际的标准文件,只有一个次要来源。 - Alexander Guyer

10

cplusplus.com提供的文档往往是不正确或不完整的。

例如,cplusplus.com上的 atoi 文档:

atoi
在返回部分中,没有提到如果函数无法进行转换,则返回值为0。

cplusplus.com返回值部分指出:“... 如果转换后的值超出了 int 可表示的值范围,则会导致未定义行为。”

这是正确的,根据标准“如果字符串的数值不能用 int 表示,则行为未定义”。

然而,该部分并不完整,因为它没有提到返回值为0,这可能会引起误解。描述段落中以前遇到过短语“...不执行转换,并返回零”,但将其包含在返回值部分中是必要的。

cplusplus.com给出的许多示例源代码都是错误的。
许多初学者参考这些资料时容易犯低级错误。

举个例子:

编辑:我之前引用的示例是不正确的。


5
也许是写错了,应该是blatant吧?然而,ballant是一个法语词,意思是“悬挂”,这可能适用于涉及指针的错误。 - hardmath
重新阅读迭代器示例...没有未定义的行为。 - Dennis Zickefoose
2
你说过:“cplusplus.com上许多示例源代码是不正确的。”然后你又删除了这个例子并说:“我之前引用的例子是错误的。”- 那么你为什么要删除这个例子呢? :) - user2962533
根据此网站,您所描述的情况导致未定义的返回类型而不是未定义行为。 http://en.cppreference.com/w/cpp/string/byte/atoi;然而,看起来Cplusplus.com更新了其文档以匹配您所说的内容。显然,他们会响应社区请求进行更正。尽管如此,我不确定哪个网站最正确,因为这两个网站陈述的内容非常不同。 - shawn1874
这个回答发布已经有9年了。人们普遍认为Cplusplus.com包含大量不正确或不完整的信息吗? - Tyler Shellberg

3
type_info的文档试图首先解释typeid,但失败了:

typeid可以直接应用于类型,返回其信息;或应用于对象,返回对象的类型信息。

typeid应用于多态类类型(即声明或继承虚函数的类)的对象的解引用指针时,它考虑其动态类型(即最派生对象的类型)。

第二段已经与第一段不符。在typeid(*ptr)中,typeid应用于表达式。这是非常重要的,因为静态类型动态类型的概念只有在表达式上下文中才有意义,而不是在对象上下文中。它也忽略了像typeid(foo())这样的情况。
此外,第二段省略了引用。它们也可以具有与所引用对象的动态类型不同的静态类型。

非常好 - RTTI问题以可预测的规律在SO上出现。知道不要引用什么是很重要的。 - Kerrek SB

3
std::pair<T1,T2>::operator==的文档说明了两个元素都会被测试以确定它们是否相等。而std::pair<T1,T2>::operator<的文档则说明只有在第一个元素相等的情况下才会考虑第二个元素。
这两种情况都出现了"相等"这个词,但是仅仅在第一种情况中它真正意味着T::operator==。而在第二种情况中,相等意味着!(a.first<b.first || b.first<a.first)

这是强制性的吗?或者如果操作符可用,库是否可以自由使用第二种情况中的 operator== - Kerrek SB
1
强制执行。C++标准不允许混合使用operator==operator< - MSalters

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接