将新放置与 std::函数一起使用不起作用

Using placement new with an std::function doesn't work

本文关键字:一起 不起作用 函数 std 新放      更新时间:2023-10-16

此代码在(*function)()时崩溃。我正在运行Visual Studio 2019并为Windows 10 x86_64编译C++17。我已经在Linux上用GCC(-std=c++17(测试过它,它工作正常。我想知道这是Visual Studio的C++编译器的问题还是我没有看到的问题。

#include <vector>
#include <array>
#include <functional>
#include <iostream>
int main() {
const size_t blockSize = sizeof(std::function<void()>);
using block = std::array<char, blockSize>;
std::vector<block> blocks;
auto lambda = [](){
std::cout << "The lambda was successfully called.n";
};
blocks.emplace_back(); 
new (&blocks[0]) std::function<void()>(lambda);
blocks.emplace_back(); 
new (&blocks[1]) std::function<void()>(lambda);
std::function<void()> *function = (std::function<void()> *)blocks[0].data();
(*function)();
return 0;
}

该错误是 std::函数内部的读取访问冲突。

当您将元素附加到std::vector并且该元素会使向量的大小大于其容量时,向量必须分配新的存储空间并将其所有元素复制/移动到新空间。 虽然您在向量中保存的char数组中构造了复杂的std::function对象,但向量并不知道这一点。 组成std::function对象的基础字节将被复制到向量的新存储中,但std::function的复制/移动构造函数不会被调用。

最好的解决方案是直接使用std::vector<std::function<void()>>。 如果出于某种原因必须使用原始存储块的向量,则需要在开始插入元素之前预先分配空间。 即

int main() {
const size_t blockSize = sizeof(std::function<void()>);
using block = std::array<char, blockSize>;
std::vector<block> blocks;
auto lambda = [](){
std::cout << "The lambda was successfully called.n";
};
blocks.reserve(2);  // pre-allocate space for 2 blocks
blocks.emplace_back(); 
new (&blocks[0]) std::function<void()>(lambda);
blocks.emplace_back(); 
new (&blocks[1]) std::function<void()>(lambda);
std::function<void()> *function = (std::function<void()> *)blocks[0].data();
(*function)();
return 0;
}

现场演示

或者,您可以使用不同的数据结构,例如在添加或删除元素时保持稳定地址的std::list