为什么将运算符void *()转换函数添加到C ++流类中? [英] Why operator void*() conversion function added to the C++ stream classes?

查看:88
本文介绍了为什么将运算符void *()转换函数添加到C ++流类中?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

C ++流类中有一个转换函数 operator void *()const 。这样所有流对象都可以隐式转换为 void * 。在与程序员进行SO交互期间,他们建议我不要使用 void * ,除非您有充分的理由使用它。 void * 是一种删除类型安全性的技术。错误检查。因此,由于存在此转换功能,因此以下程序是完全有效的。这是 C ++标准库中的缺陷。

There is a conversion function operator void*() const in C++ stream classes. so that all stream objects can be implicitly converted to void*. During the interaction with programmers on SO they suggest me to don't use void* unless you've a good reason to use it. void* is a technique of removing type safety & error checking. So, due to the existance of this conversion function following program is perfectly valid. This is a flaw in the C++ standard library.

#include <iostream>
int main()
{
       delete std::cout;
       delete std::cin;
}

观看实时演示

See live demo here.

以上程序在C ++ 03中有效,但在C ++ 11&中无法编译。以后的编译器,因为此转换功能已删除。但是问题是,如果这样做很危险,为什么它会成为C ++标准库的一部分?允许将流对象转换为 void * 的目的是什么?

The above program is valid in C++03 but fails in compilation in C++11 & later compilers, because this conversion function is removed. But question is why it was part of C++ standard library if it is dangerous? What was the purpose of allowing conversion of stream objects to void*? What is the use of it?

推荐答案

std :: stringstream 的目的是,如果流用作 bool ,则如果将流转换为 true 流仍然有效,如果不是,则为 false 。例如,如果您实现自己的词法转换版本,则可以使用一种简单的语法。

A feature of std::stringstream is that it is intended that if the stream is used as a bool, it gets converted to true if the stream is still valid and false if it's not. For instance this lets you use a simple syntax if you implement your own version of lexical cast.

(供参考, boost 包含一个名为 lexical_cast 的模板函数,其功能类似于以下简单的模板函数。)

(For reference, boost contains a template function called lexical_cast which does something similar to the following simple template function.)

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();
    }
 }

例如,如果您从事的项目有例外

If for instance, you work on a project where exceptions are disallowed, you might want to roll the following version of this instead.

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;
    }
 }

(上述方法有多种改进方法,

(There are various ways the above could be improved, this code is just to give an example.)

运算符void * 的用法如下: :


  1. ss<< u 返回对 ss 的引用。

  2. ss 隐式转换为 void * ,如果流操作失败,则为 nullptr ;如果

  3. && 运算符会迅速终止,具体取决于该指针的真值。
  4. >
  5. 第二部分 ss>> t 运行并返回,并转换为 void *

  6. 如果两项操作均成功,则我们可以返回流式结果 t 。如果其中任何一个失败,则表明存在错误。

  1. ss << u returns a reference to ss.
  2. The ss is implicitly converted to void * which is nullptr if the stream operation failed, and non-null if the stream is still good.
  3. The && operator aborts quickly, depending on the truth value of that pointer.
  4. The second part ss >> t runs, and returns and is also converted to void *.
  5. If both operations succeeded then we can return the streamed result t. If either failed then we signal an error.

布尔值转换功能基本上就是语法糖,它可以实现此目的(以及许多其他功能)

The bool conversion feature is basically just syntactic sugar that allows this (and many other things) to be written concisely.

实际上引入隐式布尔转换的缺点是 std :: stringstream 可以隐式转换为 int 以及其他许多类型,因为 bool 可以隐式转换为 int

The drawback of actually introducing an implicit bool conversion is that then, std::stringstream becomes implicitly convertible to int and many other types also, because bool is implicitly convertible to int. This ultimately causes syntactic nightmares elsewhere.

例如,如果 std :: stringstream 具有隐式的 operator bool 转换,假设您有以下简单代码:

For instance, if std::stringstream had an implicit operator bool conversion, suppose you have this simple code:

std::stringstream ss;
int x = 5;
ss << x;

现在,在重载分辨率中,您有两个潜在的重载需要考虑(!),通常是一个 operator<<(std :: stringstream& int),然后将 ss 转换为 bool ,然后提升为 int ,并且移位运算符可以应用 operator<<(int ,int),这都是因为隐式转换为 bool ...

Now in overload resolution, you have two potential overloads to consider (!), the normal one operator<<(std::stringstream &, int), and the one in which ss is converted to bool, then promoted to int, and the bit shift operator may apply operator<<(int, int), all because of the implicit conversion to bool...

解决方法是改为使用隐式转换为 void * ,该转换可以在上下文中用作布尔值,但实际上不能隐式转换为bool或int。

The workaround is to use an implicit conversion to void * instead, which can be used contextually as a bool, but isn't actually implicitly convertible to bool or int.

在C ++ 11中,我们不再需要这种解决方法,并且没有理由没有人会明确使用 void * 转换,因此将其删除。

In C++11 we don't need this workaround any more, and there's no reason that anyone would have explicitly used the void * conversion, so it was just removed.

(我在寻找参考,但我相信该函数的值仅在应该是 nullptr 不是 nullptr ,而是实现定义了它可能产生的非零指针值。因此,任何依赖 void * 版本的代码都无法正确重构以使用 bool 版本,这是不正确的

(I'm searching for a reference, but I believe that the value of this function was only specified up to when it should be nullptr vs. when it should not be nullptr, and that it was implementation defined what nonzero pointer values it might yield. So any code that relied on the void * version and cannot be trivially refactored to use the bool version would have been incorrect anyways.)

void * 解决方法仍然并非没有问题。为了增强功能,为C ++ 11之前的代码开发了更复杂的安全布尔惯用语,该iiuc基于类似 T * 的东西,其中 T 是一次使用类型,例如在实现该习语的类中定义的结构,或者对该类使用指针成员函数并使用返回值该类的特定私有成员函数或nullptr。例如,所有boost智能指针都使用安全布尔习惯用法。

The void * workaround is still not without problems. In boost a more sophisticated "safe bool" idiom was developed for pre-C++11 code, which iiuc is based on something like T* where T is either a "type-used once", like a struct which is defined in the class implementing the idiom, or using a pointer-to-member function for that class and using return values which are either a particular private member function of that class, or nullptr. The "safe bool" idiom is used for instance in all of the boost smart pointers.

尽管在C ++ 11中通过引入<$ c清除了整个混乱$ c>显式运算符bool

Regardless this whole mess was cleaned up in C++11 by introducing explicit operator bool.

此处提供更多信息:

More info here: Is the safe-bool idiom obsolete in C++11?

这篇关于为什么将运算符void *()转换函数添加到C ++流类中?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆