c++ - 为什么将 operator void*() 转换函数添加到 C++ 流类中?

标签 c++ c++11 delete-operator void-pointers c++-standard-library

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 *上面的用法如下:

  1. ss << u返回对 ss 的引用.
  2. ss隐式转换为 void *这是nullptr如果流操作失败,如果流仍然正常,则为非 null。
  3. &&运算符会快速中止,具体取决于该指针的真值。
  4. 第二部分ss >> t运行,返回,也转换为 void * .
  5. 如果两个操作都成功,那么我们可以返回流式处理结果 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 得到了清理。 .

更多信息在这里:Is the safe-bool idiom obsolete in C++11?

关于c++ - 为什么将 operator void*() 转换函数添加到 C++ 流类中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32168971/

相关文章:

c++ - std::move 在成对存储的 std::future 上

c++ - 为什么编译器在删除动态分配的内存后不自动将 NULL 分配给指针变量?

c++ - 通过引用传递未知等级的数组

c++11 - C++ : For which objects, 是 "moved"意味着超过 "staying valid"?

c++ - 数组删除给出 EXC_BAD_ACCESS 错误

c++ - 使用没有逻辑的删除

c++ - 将一些代码行包​​装到单个宏中的方法

c++ - std::ignore 用于忽略未使用的变量

c++ - DLL对执行速度的影响

c++ - 动态内存分配、指针成员和析构函数