使用 placement new 会使以下代码有效吗?
Would using placement new make the following code valid?
我正在构建一个将在 class 中使用的缓冲区,并想知道根据 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;
}
缓冲区已初始化为 char
4 字节数组。在结构顶部做一个新的放置是否允许我以 int32_t
的形式访问下面的位?我现在可以访问内存 space 作为 4 char
s(通过 buffer
对象)或作为 1 int32_t
(通过 pA
)而不违反标准?如果不行,是否可以采取其他方式?
注意:是的,我知道字节序,但在这种情况下,字节序并不重要。那是一个不同的讨论。
(为简洁起见,假设 int
和 int32_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 (&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;
我正在构建一个将在 class 中使用的缓冲区,并想知道根据 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;
}
缓冲区已初始化为 char
4 字节数组。在结构顶部做一个新的放置是否允许我以 int32_t
的形式访问下面的位?我现在可以访问内存 space 作为 4 char
s(通过 buffer
对象)或作为 1 int32_t
(通过 pA
)而不违反标准?如果不行,是否可以采取其他方式?
注意:是的,我知道字节序,但在这种情况下,字节序并不重要。那是一个不同的讨论。
(为简洁起见,假设 int
和 int32_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 (&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;