【问题标题】:What does (void *)1 mean?(void *)1 是什么意思?
【发布时间】:2019-11-19 14:29:15
【问题描述】:

我正在阅读ROS的代码。

ros_comm/roscpp/include/ros/subscriber.h文件中,我看到了这样一段代码:

operator void*() const { return (impl_ && impl_->isValid()) ? (void*)1 : (void*)0; }

嗯,(void *)0在C中可以看成NULL,但是(void *)1是什么意思呢?

如果一个类Foo包含这个函数,说明我们可以这样编码:

Foo foo;
void *ptr = foo;

对吗?那么这是否意味着void *ptr = (void *)1 是可能的?这是什么意思?

【问题讨论】:

  • 它将 1 转换为指针,将 0 转换为指针。就是这样。
  • 这是一个 c 风格的演员表。因此,它将 1 转换为 void *。至于你为什么要这样做,或者这有什么实际用途,不要问我。如果可以,请询问原始程序员,或者这里有其他人可以阐明这个问题。
  • 它可能用于定位地址为1的内存单元中的内容。不过我们不知道,请问那些运行图书馆的人。
  • 可能使用指针作为 bool 隐式转换。在现代 C++(C++11 及更高版本)中你不会这样做。
  • 我在这里查看过:github.com/ros/ros_comm/blob/melodic-devel/clients/roscpp/… 我没有看到任何地方使用的演员表。也许它是隐式使用的,但要搜索的内容很多.. 不知道..

标签: c++ casting type-conversion ros typecasting-operator


【解决方案1】:

这是在 C++11 中引入 explicit 上下文转换之前避免隐式转换到 bool 问题的老技巧。它旨在用于检查有效性:

Subscriber my_subscriber = someFunction();
if (!my_subscriber) {
    // error case
}

重要的一点是不存在从void* 到整数类型的内置转换,但确实存在从bool 到整数类型的转换。同时,存在从void*bool 的内置转换。这意味着如果你定义一个隐式转换为bool,那么下面的内容出奇地有效:

void my_func(int i);

void another_func() {
    Subscriber sub = something();
    my_func(sub);
}

定义到void* 的转换可以避免这个问题。


不过,现在这个技巧已经过时了。 C++11 引入了explicit 转换。在if 和循环的条件下考虑explicitbool 的转换,但在其他有问题的情况下不考虑。这意味着现在这种转换应该写成:

explicit operator bool() const { return impl_ && impl_->isValid(); }

【讨论】:

  • 虽然 safe bool Idiom 中使用的返回类型通常是指向成员函数的指针,因此误用的可能性更小。
【解决方案2】:

这表明编写代码的人不是很熟悉他们使用的语言或工具,或者代码已经存在了很长时间并且被不同的人入侵了,大概是在过去的某个时间经历了 C 到 C++ 的转换,仍然带有一些旧的 API 合约(期望 void*),这可能很难更改。

如果您查看源代码,则没有好的理由去做这样的事情。 impl_ 是实现 operator boolboost::shared_ptr<Impl>Impl::isValid 也返回 bool。除了bool,没有理由在任何地方使用或返回任何东西。

基本上,这是一种扭曲(并且可能很危险)的写作方式:

return impl_ && impl_->isValid();

【讨论】:

  • @Deduplicator:它确实更旧,但除此之外(explicit 关键字在这里并没有太大的区别,公开的 API 函数都没有使用它)。不过,所谓的安全布尔成语是用词不当——肮脏的黑客更适合。这绝不是安全的,也不能很好地表达意图。 bool 传达:“这是一个是或否值”,而 void* 传达“我是一个指针,请取消引用我”。对于(void*)0(void*)1,这通常不是一个好主意。当偶然以不同方式使用时它“起作用”这一事实是无关紧要的。
  • 编程不仅仅是“适合我”甚至“我相信”,而是要确保事情是定义明确、表达明确、明确无误、提供可重现的结果,并尽可能保证故障安全。调用该函数的人必须立即知道如何处理返回值,而无需查阅 20 页的文档。 void* 并非如此。 “是的,但是有一个隐式转换为...任何东西”的概念并不是很好。
  • 没有人会否认安全布尔成语是一个肮脏的黑客,这意味着。不幸的是,这也是 C++11 之前可以做到的最好的。而且我只引用了boost::shared_ptr 的历史,因为虽然您承认所讨论的代码可能很古老,但您好奇地使用该库的当前版本作为所使用语言版本的论据。
  • @Deduplicator:我不得不承认我不太熟悉 1990 年代中后期的 Boost 版本 :-) 虽然我很确定 return !!m_ptr; 很好——已经在 80 年代后期定义并完美可靠地工作(显然,除了没有 explicit 关键字)。打我为什么,为了防止几乎无害的可能且很少发生 bool-to-int 转换,人们会牺牲清晰度和表现力。
猜你喜欢
  • 2017-12-23
  • 1970-01-01
  • 1970-01-01
  • 2020-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-03-09
相关资源
最近更新 更多