繁体   English   中英

在没有警告/错误的情况下对引用进行隐式重新解释

implicit reinterpret cast on reference without warning/error

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

刚刚发现阴险崩溃的原因是编译器不加思索的狂野演员 ,无视类型。 这是预期的行为还是编译器错误?

问题 :当涉及类型定义时,可以进行隐式重新解释转换,从而破坏类型系统。

#include <iostream>

template<class A, class B>
inline bool
isSameObject (A const& a, B const& b)
{
  return static_cast<const void*> (&a)
      == static_cast<const void*> (&b);
}


class Wau
  {
    int i = -1;
  };

class Miau
  {
  public:
    uint u = 1;
  };


int
main (int, char**)
{
  Wau wau;
  using ID = Miau &;
  ID wuff = ID(wau);      // <<---disaster

  std::cout << "Miau=" << wuff.u
            << " ref to same object: " <<std::boolalpha<< isSameObject (wau, wuff)
            << std::endl; 
  return 0;
}

我很震惊地发现gcc-4.9,gcc-6.3和clang-3.8接受此代码没有任何错误并产生以下输出:

Miau=4294967295 ref to same object: true

请注意我使用类型构造函数语法ID(wau) 我希望在C风格的演员(ID)wau上有这样的行为,即(ID)wau 只有在使用新式花括号语法ID{wau}我们ID{wau}得到预期的错误...

~$ g++ -std=c++11 -o aua woot.cpp

woot.cpp: In function ‘int main(int, char**)’:
woot.cpp:31:21: error: no matching function for call to ‘Miau::Miau(<brace-enclosed initializer list>)’
     ID wuff = ID{wau};
                 ^
woot.cpp:10:7: note: candidate: constexpr Miau::Miau()
 class Miau
       ^~~~
woot.cpp:10:7: note:   candidate expects 0 arguments, 1 provided
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(const Miau&)
woot.cpp:10:7: note:   no known conversion for argument 1 from ‘Wau’ to ‘const Miau&’
woot.cpp:10:7: note: candidate: constexpr Miau::Miau(Miau&&)
woot.cpp:10:7: note:   no known conversion for argument 1 from ‘Wau’ to ‘Miau&&’

不幸的是,由于std::initializer_list fiasco,大括号语法通常是模板重码中的禁忌。 所以对我来说这是一个严重的问题,因为类型系统的保护在这里有效地破坏了。

  • 有人可以解释这种行为背后的原因吗?
  • 它是某种向后兼容性(再次,叹息)?
2 个回复

可以进行隐式重新解释转换,破坏类型系统。

 ID wuff = ID(wau); 

这不是一个“隐含的”重新诠释。 这是一种显式类型转换。 虽然转换确实重新解释的事实确实不容易看到。 具体来说,强制转换的语法称为“功能样式”。

如果您不确定哪种类型的强制类型转换(无论是使用函数语法还是C样式语法)执行,那么您应该避免使用它。 许多人认为永远不应该使用显式类型转换。

如果您使用的是static_cast ,那么您将保持在类型系统的保护范围内:

ID wuff = static_cast<ID>(wau);

error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'

简单地依赖隐式转换通常也是安全的:

ID wuff = wau;

error: non-const lvalue reference to type 'Miau' cannot bind to a value of unrelated type 'Wau'

这是预期的行为吗?

是。

还是编译错误?

没有。

要成为完全语言律师, T(expression)expression结果到T 1转换 此转换与调用类的构造函数2有效 这就是为什么我们倾向于调用非显式构造函数,只使用一个参数作为转换构造函数

using ID = Miau &;
ID wuff = ID(wau);

这相当于对ID强制转换表达式 由于ID不是类类型,因此会发生C样式转换。

有人可以解释这种行为背后的原因吗?

我真的不知道为什么它曾经是C ++的一部分。 这不是必需的。 这是有害的。

它是某种向后兼容性(再次,叹息)?

不一定,使用C ++ 11到C ++ 20,我们已经看到了重大变化。 这可以在某一天删除,但我怀疑它会。


1)

[expr.type.conv]

  1. simple-type-specifiertypename-specifier后跟带括号的可选表达式列表braced-init-list (初始化程序),在给定初始化程序的情况下构造指定类型的值。 [...]
  2. 如果初始值设定项是带括号的单个表达式,则类型转换表达式等效于相应的强制转换表达式 [...]

2) (当T是类类型并且存在这样的构造函数时)

[class.ctor]/2

构造函数用于初始化其类类型的对象。 因为构造函数没有名称,所以在名称查找期间永远不会找到它们; 但是,使用函数表示法([expr.type.conv])的显式类型转换将导致调用构造函数来初始化对象。

1 如何在不引起UB的情况下将字节序列重新解释为POD结构?

假设我们将一些数据作为一个字节序列获得,并希望将该序列重新解释为一个结构(有一些保证数据确实是正确的格式)。 例如: 现在magic_reinterpret实际上是坏的,因为它打破了严格的别名规则,从而导致UB。 如何实现它不会导致UB而不是像memcpy那样做任何数据副本? ...

2 在托管环境中无需接口/装箱的情况下重新解释结构仿真器

我有一个用于模拟(不可派生的)结构并添加功能(事件)的类 它具有完全相同的公共接口,但有一些自定义内部代码,可用于发生突变的事件。 我需要将所述类传递给期望类模拟的结构的函数,但由于装箱速度太慢,因此需要避免装箱/拆箱。 如果模拟的结构不在我的控制之下,并且不是从接口派生的,我如何 ...

3 如何在不创建新实例的情况下进行隐式转换?

我有一堂课,看起来像这样 现在,当我将类的值分配给字符串时,我将获得myData的值。 但是在Microsoft的示例中 ,要执行从MyClass到string隐式对流,我必须在静态方法中创建MyClass的新实例。 我不想这样做,而是想简单地将字符串的值分配给myData字段。 ...

4 重新解释断点

我使用在运行时加载的groovy脚本。 我将编译器自定义添加到该groovy脚本中。 一个例子是 将更改为 我将自定义参数注入所有函数,并添加代码以在函数内部使用它。 我面临的问题是:a)我试图在功能1的intellij中放置一个断点b)它可以让我做到这一点c)但是当我执行 ...

6 在没有RValue隐式转换的情况下正确实现

我遇到了一个问题,RValue不允许隐式转换。 我的问题是,哪种实施方案更好地“绕过”此限制? 这是示例代码说明问题: 可以利用RValue但函数需要基数且参数为派生失败的所有调用。 选项1 解决方案1: 此选项要求用户在调用函数之前将派生对象转换为基本对象。 ...

9 隐式反馈情况下的Mahout建议

我正在使用Mahout框架,以便使用众所周知的movielens数据集(ml-100k)在隐式反馈上下文中获得建议,该数据集已二值化,考虑到所有评级等于4或5,其他评级等于0。 在此数据集中,有五个拆分,每个拆分通常都分为测试集和训练集。 在推荐过程中,我使用简单的GenericBool ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2021 STACKOOM.COM