C++流类中有一个转换函数operator void*() const
。以便所有流对象都可以隐式转换为 void*
。在与 SO 上的程序员互动期间,他们建议我不要使用 void*
,除非你有充分的理由使用它。 void*
是一种消除类型安全和错误检查的技术。 因此,由于此转换函数的存在,以下程序是完全有效的。这是 C++ standard library. 中的一个缺陷。
#include <iostream>
int main()
{
delete std::cout;
delete std::cin;
}
观看现场演示 here.
上述程序在 C++03 中有效,但在 C++11 及更高版本的编译器中编译失败,因为此转换功能已被删除。但问题是,如果它很危险,为什么它是 C++ 标准库的一部分?允许将流对象转换为 void*
的目的是什么?它有什么用?
最佳答案
std::stringstream
的一个功能是否打算将流用作 bool
, 它被转换为 true
如果流仍然有效并且 false
如果不是。例如,如果您实现自己的词法转换版本,这可以让您使用简单的语法。
(作为引用,boost
包含一个名为 lexical_cast
的模板函数,它的作用类似于以下简单的模板函数。)
template <typename T, typename U>
T lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
throw bad_lexical_cast();
}
}
例如,如果您在一个不允许异常(exception)的项目中工作,您可能希望转而使用以下版本。
template <typename T, typename U>
boost::optional<T> lexical_cast(const U & u) {
T t;
std::stringstream ss;
if (ss << u && ss >> t) {
return t;
} else {
return boost::none;
}
}
(上面的改进方法有很多种,这段代码只是举例)
operator void *
上面的用法如下:
-
ss << u
返回对ss
的引用. ss
隐式转换为void *
这是nullptr
如果流操作失败,如果流仍然正常,则为非 null。&&
运算符会快速中止,具体取决于该指针的真值。- 第二部分
ss >> t
运行,返回,也转换为void *
. - 如果两个操作都成功,那么我们可以返回流式处理结果
t
.如果其中任何一个失败,我们就会发出错误信号。
bool 转换功能基本上只是语法糖,它允许简洁地编写此(以及许多其他内容)。
实际引入隐式 bool 转换的缺点是,std::stringstream
隐式转换为 int
以及许多其他类型,因为 bool
可隐式转换为 int
.这最终会导致其他地方的语法噩梦。
例如,如果 std::stringstream
有一个隐含的 operator bool
转换,假设你有这个简单的代码:
std::stringstream ss;
int x = 5;
ss << x;
现在在重载解决方案中,您需要考虑两个潜在的重载 (!),一个是正常的 operator<<(std::stringstream &, int)
,以及其中 ss
转换为 bool
,然后提升为 int
, 并且位移运算符可以应用 operator<<(int, int)
, 都是因为隐式转换为 bool
...
解决方法是使用隐式转换为 void *
相反,它可以在上下文中用作 bool,但实际上不能隐式转换为 bool 或 int。
在 C++11 中,我们不再需要这种变通方法,而且没有任何人会明确使用 void *
转换,所以它被删除了。
(我正在寻找引用,但我相信这个函数的值只指定到它应该是 nullptr
与它不应该是 nullptr
的时间,并且它是实现定义的它可能会产生什么非零指针值。因此,任何依赖于 void *
版本并且无法简单重构以使用 bool
版本的代码无论如何都是不正确的。)
void *
解决方法仍然不是没有问题。在 boost 中,为 C++11 之前的代码开发了一个更复杂的“安全 bool ”习语,iiuc 基于 T*
之类的东西。在哪里 T
要么是“类型使用一次”,例如在实现该习语的类中定义的结构,要么使用该类的指向成员函数并使用返回值,该值是该类的特定私有(private)成员函数, 或 nullptr。例如,在所有 boost 智能指针中都使用了“安全 bool ”习语。
尽管这整个困惑在 C++11 中通过引入 explicit operator bool
得到了清理。 .
关于c++ - 为什么将 operator void*() 转换函数添加到 C++ 流类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32168971/