繁体   English   中英

std::launder 可达性规则

[英]std::launder reachability rules

std::launder示例具有以下代码块:

int x2[2][10];
auto p2 = std::launder(reinterpret_cast<int(*)[10]>(&x2[0][0])); 
// Undefined behavior: x2[1] would be reachable through the resulting pointer to x2[0]
// but is not reachable from the source

什么? 来自std::aligned_storage的示例让我觉得情况并非如此:

std::aligned_storage_t<sizeof(T), alignof(T)> data[N];

// Access an object in aligned storage
const T& operator[](std::size_t pos) const 
{
    // Note: std::launder is needed after the change of object model in P0137R1
    return *std::launder(reinterpret_cast<const T*>(&data[pos]));
}

这就是混淆的地方: &data[pos]只是&data[pos][0] ,因为&p == &p[0]其中p是一个数组

如果std::aligned_storage除了像alignas(T) std::byte[sizeof (T)];类的其他方式之外几乎不能以任何其他方式实现,那这怎么行? ? 结构中的数组是否以某种方式神奇地使它变好? 为什么?

假设我有

template <typename T>
using uninitialized = alignas(T) std::byte[sizeof (T)];

constexpr auto N = 5;
uninitialized<int> array[N];
for (std::size_t i = 0; i < N; i++) {
    new (&array[i]) int(i);
}

怎么办? 是不是任何演员都喜欢

auto laundered_value_ptr = std::launder(reinterpret_cast<int*>(&array[i]));

和第一个例子一样吗? 那这个呢:

auto laundered_array_ptr = std::launder(reinterpret_cast<int*>(array));
laundered_array_ptr[0] = 9;
laundered_array_ptr[2] = 76;

如果我遵循,似乎没有办法正确使用这个 memory,因为使用std::byte(*)[sizeof (int)]意味着它周围的任何东西基本上都是可以访问的,并且在第一个例子之后,所有写在这个问题是也可能是UB。

我使用g++ -g -O0 -Wextra -Wall -Wpedantic -std=c++20 -fsanitize=undefined -fsanitize=address编译了这些示例,奇怪的是甚至没有收到让我完全难过的警告。

我怀疑这根本不重要,但这是我正在使用的编译器版本。

g++ (GCC) 12.1.1 20220730

你写了:

&data[pos]只是&data[pos][0] ,因为&p == &p[0]其中p是一个数组。

事实上,事实并非如此。 如果p是一个数组(将其类型称为T[N] ),则表达式&p == &p[0]将无法编译。 左侧的类型为T(*)[N] ,右侧的类型为T* 这些无法直接比较,就像您无法将int*char*进行比较一样。

但是, static_cast<void*>(&p) == static_cast<void*>(&p[0])将是真的。

两个指针代表同一个地址,但不能互相替代。

&data[pos]是指向data一个元素的指针,所有其他data元素都可以通过它访问。 另一方面,(假设std::aligned_storage_tunsigned char数组的别名) &data[pos][0]仅指向data元素的单个元素; 它并不指向整个data元素。 所以data[pos]的所有其他元素都可以通过它访问,但data的其他元素不是。

由于data的所有元素都可以通过&data[pos]访问,因此data中的所有字节都可以通过&data[pos]访问。 在此指针转换为const T*后,存储在data的其他元素中的其他T也可以从结果指针访问,但这些T的字节也可以从原始指针访问,所以满足std::launder的先决条件。

如果我们使用&data[pos][0]作为reinterpret_cast的参数,则只能从该指针访问单个元素data[pos]中的字节,并且不会满足先决条件。

暂无
暂无

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

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