【问题标题】:Does simple overlap of memory in variables violate aliasing rules?变量中内存的简单重叠是否违反了别名规则?
【发布时间】:2018-02-14 11:27:47
【问题描述】:

为了有效地获得编译时大小的数组的编译时大小的子范围视图。

我使用这种技术已经有一段时间了,因为我从来没有收到警告或错误,所以我认为它没问题。

std::array<int,3> aa = {{1,2,3}};
std::array<int,2>& ee = reinterpret_cast<std::array<int,2>&>(aa[1]); // subrange {{2,3}}
assert(ee[0] == 2);

直到我找到这些cmetshttps://stackoverflow.com/a/36046533/225186

我可以让gcc 产生警告

int aaa = 5;
double& eee = reinterpret_cast<double&>(aaa);

或者这个

std::array<int,3> aaaa = 5;
std::array<double,2>& eeee = reinterpret_cast<std::array<double,2>&>(aaaa);

...但不是第一个代码块。

如果两个引用不在同一个地址,似乎不会强制执行别名规则?


似乎每个人都同意这至少是 UB。 这样可以吗?还是更糟糕?

int aa[3] = {1,2,3};
int* ee = new(&aa[1]) int[2];

如果我可以说int ee[2] = new(&amp;aa[1]) int[2]; 那就完美了,因为ee 的类型将带有新的大小,并且我可以递归地使用子视图。

我可以为此使用std::basic_string_view&lt;int&gt; 吗? 在 cppreference 中,唯一的限制是 int 必须是 char-like。 (我认为是。)

【问题讨论】:

  • 不确定是不是规则被破坏了,但它是迂腐的UB,&amp;aa[1]没有对象std::array&lt;int,2&gt;...
  • 也许如果你改写你的问题,解释你为什么想做你正在做的事情,有人可以建议一种便携的方式来做。我无法确切地说出你为什么要做你正在做的事情,我相信这是有原因的......
  • 我认为你打破了这一点:“任何两个具有重叠生命周期的对象(不是位字段)都保证具有不同的地址,除非其中一个是另一个的子对象或提供存储对于另一个,..." 来自:en.cppreference.com/w/cpp/language/object
  • 我怀疑如果你真的需要一个类似 std::array 的子数组访问,那么前进的道路将是一些具有 std::array 语义的子范围引用对象。我可以很容易地看到这样一个参考类的优势,可能类似于 std::string_view。
  • 我不确定您是否可以依靠 std::array 实现来没有私有管理成员。是的,它们必须毫无例外地构造,因此没有动态分配,并且它们必须封装并表现得像一个 c 样式的数组而不发布任何其他非静态成员,但假设引用“随机数”是不正确的" 内存将正确构造数组。

标签: c++ c++11 strict-aliasing stdarray


【解决方案1】:
std::array<int,3> aa = {{1,2,3}};
std::array<int,2>& ee = reinterpret_cast<std::array<int,2>&>(aa[1]);

绝对违反了严格的别名规则,对ee的访问是未定义的行为

cppreference/reinterpret_cast/type aliasing:


...但不是第一个代码块。

如果您的编译器没有产生警告,这并不意味着一切正常 - 标准没有强制要求警告。编译器会尽可能提供帮助,但它们不会检测到所有违反标准的情况。

【讨论】:

    猜你喜欢
    • 2020-04-11
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    • 2016-02-24
    • 2019-05-04
    相关资源
    最近更新 更多