【问题标题】:delete cout; delete cin; do not give compilation error - a flaw in the Standard library?删除cout;删除cin;不要给出编译错误 - 标准库中的缺陷?
【发布时间】:2011-09-17 08:42:04
【问题描述】:

下面会报编译错误吗?

delete cout;
delete cin;

答案是:没有。

这是标准库中流类的实现中的一个缺陷。它们具有以下到void*类型的转换函数,这意味着所有流对象都可以隐式转换为void*

operator void * ( ) const;

这通常非常有用,因为它可以让我们写very idiomatic loop,例如,当从文件中读取输入时。但同时,它允许用户写delete stream。正如我所说,您可以删除任何流对象。所以所有这些都是允许的:

delete ss;  //declare std::stringstream ss;
delete iss; //declare std::istringstream iss;
delete oss; //declare std::ostringstream oss;

只是他们会发出警告,说(见ideone):

警告:删除‘void*’是未定义的

你可以easily avoid 只需将其转换为char*。但是程序还是有问题,运行时很可能会崩溃。

--

所以我的问题是,这个问题是否在 C++11 中得到解决和修复?以下文章提供了一个解决此问题的方法:

--

编辑:

来自@Xeo 对@Alf 回答的评论:

提出解决此问题的论文:

【问题讨论】:

  • c++ 为您提供了很多方法来让自己在脚下开枪。这是其中之一 ;)
  • 我会说这是直射眼睛! :-)
  • 幸运的是,有一个简单的解决方法,用“那么不要那样做”的语言:)
  • @Nawaz:Safe Bool 习语是在 C++98 发布之后发明的(我不知道 C++03),所以这很正常。请注意,尽管他们已经有所考虑,因为他们使用 void*(在大多数情况下会发出警告)而不是直接使用 char*bool
  • 你不应该更担心memcpy(cout, cin, 10); 没有任何警告。

标签: c++ stream c++11 implicit-conversion


【解决方案1】:

它显然已经修复了。

至少,在 N3290 中,您有 std::basic_ios::operator bool 而不是 void* 转换,并且此 operator bool 声明为 explicit

请注意,C++98/C++03 不支持explicit 类型转换运算符,但 C++11 支持。

explicit 类型转换运算符

N3290 §12.3.2/2;
仅被视为用户定义的转换 用于直接初始化 (8.5)

这对于 condition 来说似乎是不切实际的,例如whilefor 声明。

很高兴,

N3290 §4/3;
对于某些发明的临时变量t (8.5),当且仅当声明 T t=e; 格式正确时,表达式 e 可以隐式转换为类型 T。某些语言结构要求将表达式转换为布尔值。 出现在这种上下文中的表达式e 被称为在上下文中转换为bool,并且当且仅当声明bool t(e); 是格式正确的,对于某些发明的临时变量t (8.5)。任一隐式转换的效果与执行 声明和初始化,然后使用临时变量作为转换的结果。

其中bool t(e); 是一个直接初始化

例如您不必显式转换用作while 中的条件的流对象,因为隐式转换(嘿嘿)。

不幸的是,搜索 N3290 我找不到任何发生这种情况的“某些语言结构”列表,但在 cmets 中,JohannesD 写道:

通过 FDIS 搜索“contextually”,整个列表似乎是:ifwhiledofornoexceptstatic_assert条件; ?: 的第一个操作数;两个都 &&|| 的操作数;和 ! 的操作数。

干杯,

【讨论】:

  • 是的,这就是愚蠢的 C++11“隐式显式”。呵呵。 :-)
  • 并且它也被固定在核心语言方面。 delete 运算符现在只考虑到指针对象类型的转换函数。因此,现在需要进行诊断,而不是这种情况具有未定义的行为。当然,这不需要正式更改他的实施(他已经得到了诊断),但现在很可能实施将拒绝而不是仅仅警告......
  • 这是标准转换 i 第 4 条的一部分:“某些语言结构要求将表达式转换为布尔值。出现在这种上下文中的表达式 e 被称为是上下文转换的对于某些发明的临时变量t,当且仅当声明bool t(e); 格式正确时,才为布尔型且格式正确。”显然,Alf 觉得“上下文转换”使用显式运算符来执行过去的隐式转换很有趣。
  • 在 FDIS 中搜索“contextually”,整个列表似乎是:ifwhiledofornoexceptstatic_assert 条件; ?: 的第一个操作数; &&|| 的两个操作数;和!的操作数。
【解决方案2】:

如果我能给我的 2 美分,我认为标准库有点“缺陷”,出于善意。

operator void*() 已被引入以允许类似的代码 while(stream)if(!stream)while(stream && ...),不提供对整数运算的隐式访问(operator bool 应该提供的)。 事实上,这禁用了整数运算,但可以访问指针功能(如删除...)。

现在,在 C++0x 中,引入了 explicit oeprator bool()。它不会隐式授予对任何功能的访问权限,因为它需要隐式转换。但是……等一下:'while(bool(stream))' 甚至 while(static_cast<bool>(stream)) 都太罗嗦了…… 操作员 !是明确的,并且 'while(!!stream)' 看起来如此有效,我什至想知道为什么不接受它作为范例:

如果我想将某些内容显式转换为布尔值,我只需提供一个operator!() 并给! 表示“无效”和!! 为“有效”。

比隐式转换安全得多,而且不会冗长:毕竟! 永远存在!

【讨论】:

  • 您不必编写while(!!stream),因为explicit 转换是为while 和其他需要bool 值的构造隐式调用的。看我的回答。干杯&hth.,
  • 您可能想查找“安全布尔成语”。 (或者不要,因为它在 C++11 中已经过时了。)我尝试使用 !! 一段时间,并认为丑陋不值得边际安全......
  • @Alf:是的,使用新编译器不再重要,但是使用旧编译器...我看到了很多技巧,只是为了避免键入 a ! .... 无论如何,谢谢。
  • @Potatoswatter:这是一个品味问题……C++ 中还有很多其他丑陋的东西……
猜你喜欢
  • 2020-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-12
  • 1970-01-01
  • 2020-03-15
  • 1970-01-01
  • 2023-02-11
相关资源
最近更新 更多