使用 placement new 正确分配数组
Properly allocate an array with placement new
我正在构建内存分配器并使用 placement new。
假设我想将 "place" 10 个元素添加到堆上已分配的数组中。
首先常规 new 在堆上分配必要数量的字节,然后我在适当的位置构造我的 WE
对象。
struct WE {
WE() {
std::cout << "WE default constructed\n";
}
~WE() {
std::cout << "WE default destructed\n";
}
double d;
int i;
char c;
};
placement new 的以下用法是否正确?
代码编译输出似乎正确,但我有一些疑问。
// 1. allocate
const int elements = 10;
int nbytes = elements * sizeof(WE);
char* memory = new char[nbytes];
WE* pB = (WE*)memory;
int step = sizeof(WE);
// 2. construct
for (int i = 0; i < nbytes; i += step)
new (pB + i) WE();
// 3. process
for (int i = 0; i < nbytes; i += step)
pB[i].i = i * 2;
for (int i = 0; i < nbytes; i += step)
std::cout << '[' << i << ']' << '=' << pB[i].i << '\n';
// 4. destruct
for (int i = 0; i < nbytes; i += step)
pB[i].~WE();
// 5. deallocate
delete[] memory;
pB = nullptr;
memory = nullptr;
如果上面的问题都没有问题,那么请允许我再问一个问题,我将如何在任意字节边界上对齐这个数组?
假设我想要对齐 sizeof(WE)
,即 16
(而不是 alignof(WE)
,即 8
)。这个修改: alignas(sizeof(WE)) char* memory = new char[nbytes];
是否足以解决问题?我也听说过std::aligned_storage
。我不确定它是否可以提供任何好处。 (如果第二个问题让您感到困惑,或者如果我在第 1 部分搞砸了,那就算了。)提前致谢。
对于对象构造(新放置),您可以迭代 byte/char-wise:
for (int i = 0; i < nbytes; i += step) new (memory + i) WE();
或元素方面:
for (int i = 0; i < elements; i++) new (pB + i) WE();
在其余的循环中,您访问元素的地方,您需要使用第二个选项。
至于对齐,动态内存分配returns 内存块在alignof(std::max_align_t)
(C++11) 处对齐。示例值是 16 (GCC/x86_64),这是你想要的,但这个值当然不是标准所保证的。
如果我没记错的话,在 C++17 之前 operator new
不能直接为过度对齐的对象分配内存,std::aligned_storage
在这里也无济于事。从 C++17 开始,operator new
有接受对齐信息的特殊版本,参见:https://en.cppreference.com/w/cpp/memory/new/operator_new.
我正在构建内存分配器并使用 placement new。 假设我想将 "place" 10 个元素添加到堆上已分配的数组中。
首先常规 new 在堆上分配必要数量的字节,然后我在适当的位置构造我的 WE
对象。
struct WE {
WE() {
std::cout << "WE default constructed\n";
}
~WE() {
std::cout << "WE default destructed\n";
}
double d;
int i;
char c;
};
placement new 的以下用法是否正确?
代码编译输出似乎正确,但我有一些疑问。
// 1. allocate
const int elements = 10;
int nbytes = elements * sizeof(WE);
char* memory = new char[nbytes];
WE* pB = (WE*)memory;
int step = sizeof(WE);
// 2. construct
for (int i = 0; i < nbytes; i += step)
new (pB + i) WE();
// 3. process
for (int i = 0; i < nbytes; i += step)
pB[i].i = i * 2;
for (int i = 0; i < nbytes; i += step)
std::cout << '[' << i << ']' << '=' << pB[i].i << '\n';
// 4. destruct
for (int i = 0; i < nbytes; i += step)
pB[i].~WE();
// 5. deallocate
delete[] memory;
pB = nullptr;
memory = nullptr;
如果上面的问题都没有问题,那么请允许我再问一个问题,我将如何在任意字节边界上对齐这个数组?
假设我想要对齐 sizeof(WE)
,即 16
(而不是 alignof(WE)
,即 8
)。这个修改: alignas(sizeof(WE)) char* memory = new char[nbytes];
是否足以解决问题?我也听说过std::aligned_storage
。我不确定它是否可以提供任何好处。 (如果第二个问题让您感到困惑,或者如果我在第 1 部分搞砸了,那就算了。)提前致谢。
对于对象构造(新放置),您可以迭代 byte/char-wise:
for (int i = 0; i < nbytes; i += step) new (memory + i) WE();
或元素方面:
for (int i = 0; i < elements; i++) new (pB + i) WE();
在其余的循环中,您访问元素的地方,您需要使用第二个选项。
至于对齐,动态内存分配returns 内存块在alignof(std::max_align_t)
(C++11) 处对齐。示例值是 16 (GCC/x86_64),这是你想要的,但这个值当然不是标准所保证的。
如果我没记错的话,在 C++17 之前 operator new
不能直接为过度对齐的对象分配内存,std::aligned_storage
在这里也无济于事。从 C++17 开始,operator new
有接受对齐信息的特殊版本,参见:https://en.cppreference.com/w/cpp/memory/new/operator_new.