【问题标题】:Would using placement new make the following code valid?使用placement new 会使以下代码有效吗?
【发布时间】:2022-01-01 14:25:53
【问题描述】:

我正在构建一个将在类中使用的缓冲区,并想知道根据 C++ 标准以下内容是否有效:

#include <iostream>
#include <cstdint>

int main() {
  alignas(std::int32_t) char A[sizeof(std::int32_t)] = { 1, 0, 0, 0 };
  std::int32_t* pA = new (&A) std::int32_t;
  std::cout << *pA << std::endl;
  return 0;
}

缓冲区已初始化为 4 字节的 char 数组。在结构顶部放置一个新位置是否允许我以int32_t 的形式访问下面的位?我现在可以以 4 个chars(通过buffer 对象)或 1 个int32_t(通过pA)访问内存空间而不违反标准吗?如果不行,有没有其他办法?

注意:是的,我知道字节序,但在这种情况下,字节序无关紧要。那是一个不同的讨论。

【问题讨论】:

  • 不,现在你不能直接访问A(它的生命周期已经结束)并且读取*pA会读取一个未初始化的int,这也是未定义的行为。
  • @FrançoisAndrieux,有没有办法让编译器将其视为已初始化?必须有,因为一直有从文件和流中读取的缓冲区。
  • 不,你不能。像这样的内置类型无法共享相同的内存表示并同时可访问。
  • memcpy 是诀窍。
  • 使用 std::bit_cast 进行类型双关。

标签: c++ placement-new


【解决方案1】:

(为简洁起见,假设intint32_t 是同一类型)

在 C++20 中,由于 A 是一个字符数组,所以 int 类型的对象可以是 在A 中隐式创建,因此只需要以下内容:

alignas(int) char A[sizeof(int)] = { 1, 0, 0, 0 };
int * pA = reinterpret_cast<int*>(&A[0]);
std::cout << *pA << std::endl;

原始new (&amp;A) int 的问题在于它结束了已初始化的原始char[sizeof(int)] 对象的生命周期,因此无法读取其值。你现在有一个默认初始化的int,它是 UB 可以读取的。因此,您的原始代码相当于:

int A;
std::cout << A << std::endl;

如果您不能依赖 C++ 20 隐式对象创建,则可以使用类型双关语方法,该方法创建具有相同“位模式”(值表示)的不同类型的对象。可以使用std::bit_cast(或使用std::memcpy 实现的版本):

char A[sizeof(int)] = { 1, 0, 0, 0 };
int B = std::bit_cast<int>(A);
std::cout << B << std::endl;

或者std::memcpy直接复制值表示:

char A[sizeof(int)] = { 1, 0, 0, 0 };
int B;
std::memcpy(&B, A, sizeof(int));
std::cout << B << std::endl;

可以使用placement new 将A 的有效类型从char[sizeof(int)] 更改为int,如下所示:

alignas(int) char A[sizeof(int)] = { 1, 0, 0, 0 };
// `A` has effective type `char[sizeof(int)]`; cannot be accessed through `int*`

int * pA = new (&A) int(std::bit_cast<int>(A));
// `A` now has effective type `int`. This line should be optimised to do nothing to `A` at runtime.

std::cout << *pA << std::endl;

// Or using `A` directly
std::cout << *std::launder(reinterpret_cast<int*>(A)) << std::endl;

【讨论】:

  • 很好的解释。谢谢。
猜你喜欢
  • 1970-01-01
  • 2018-05-13
  • 1970-01-01
  • 1970-01-01
  • 2013-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-29
相关资源
最近更新 更多