为什么我们不能简单地复制 std::function
Why can't we trivially copy std::function
我要求这样做的原因是我需要将 std::function
存储在向量中,如果需要更多内存,我们在公司中拥有的内部向量基本上是在进行realloc。(基本上只是memcpy
,无需复制/移动操作员)
这意味着我们可以放入容器中的所有元素都需要琐碎的拷贝。
这是一些代码,以演示我有问题的副本:
void* func1Buffer = malloc(sizeof(std::function<void(int)>));
std::function<void(int)>* func1p = new (func1Buffer) std::function<void(int)>();
std::function<void(int)>* func2p = nullptr;
*func1p = [](int) {};
char func2Buffer[sizeof(*func1p)];
memcpy(&func2Buffer, func1p, sizeof(*func1p));
func2p = (std::function<void(int)>*)(func2Buffer);
// func2p is still valid here
(*func2p)(10);
free(func1Buffer);
// func2p is now invalid, even without std::function<void(int)> desctructor get triggered
(*func2p)(10);
我知道我们应该支持元素的复制/移动,以便安全存储std::function
。但是我仍然非常好奇上面std::function
复制的直接原因是什么。
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------- Updateline ----------------------------------------------------------------------------------------------------
更新了代码样本。
我通过更多地调试我们的内部向量,找到了这种失败的直接原因。
琐碎复制的 std::function
对原始对象内存有一定的依赖性,删除原始内存将丢弃不复制的 std::function
,甚至没有,而没有的破坏原始对象。
感谢大家对此帖子的回答。这都是有价值的输入。:)
问题是必须如何实现std::function
:它必须管理其持有的任何对象的寿命。因此,当您写作时:
{
std::function<Sig> f = X{};
}
当f
脱离范围时,我们必须调用X
的破坏者。此外,std::function
将[有潜在的]分配内存以保持X
,因此f
的破坏者还必须[可能]释放该内存。
现在考虑当我们尝试做什么时会发生什么:
char buffer[100000]; // something big
{
std::function<void()> f = X{};
memcpy(buffer, &f, sizeof(f));
}
(*reinterpret_cast<std::function<void()>*>(buffer))();
在我们将函数称为"存储"在buffer
处的
,X
对象已经被破坏,并且持有的内存已被释放。无论X
是否为TriviallyCopyable
,我们都没有X
。我们的艺术家以前称为X
。
由于std::function
负责管理自己的对象,因此它也不能是TriviallyCopyable
,即使,我们还添加了要求其管理的所有可销售的要求均为TriviallyCopyable
。
要在realloc_vector
中工作,您需要需要function_ref
(或std::function<>*
)之类的东西(即,一种根本不拥有任何资源的类型),或者您需要实现自己的function
版本(a)保留自己作为成员的存储,以避免分配内存和(b)仅使用TriviallyCopyable
可呼叫物构造,以便它本身变得琐碎地复制。无论哪种解决方案更好,都取决于您的程序实际在做什么。
,但我仍然非常好奇什么是无效的直接原因 std ::函数副本上方。
std::function
不能为TriviallyCopyable
(或有条件的TriviallyCopyable
),因为作为通用可呼叫对象包装器,它不能假设存储的可callable是TriviallyCopyable
。
考虑实现自己的std::function
版本,该版本仅支持TriviallyCopyable
可呼叫对象(使用固定的缓冲区进行存储),或使用功能指针向量(如果适用于您的情况)。
要琐碎地复制是与给定类型的固有相关的东西,而不是与对象有关。
考虑以下示例:
#include<type_traits>
#include<functional>
int main() {
auto l = [](){};
static_assert(not std::is_trivially_copyable<decltype(l)>::value, "!");
std::function<void(void)> f;
bool copyable = std::is_trivially_copyable<decltype(f)>::value;
f = l;
// do something based on the
// fact that f is trivially copyable
}
分配给函数的lambda,您如何执行该属性?
您要寻找的是一种运行时机械,该机械基于分配给该功能的实际对象而获得决定。
这不是std::is_trivially_copyable
的工作方式。
因此,编译器必须在编译时就std::function
的给定专业化做出决定。因为它是可呼叫对象的通用容器,您可以将其分配给它的可复制对象以及不容易复制的对象,其余的不用说。
std ::函数可能为捕获的变量分配内存。与分配内存的任何其他类一样,它也不是可复制的。
- Confusion: decltype vs std::function
- 为什么 std::function 可以作为 std::not2 的参数?
- 'max'匹配'std::function<const int &(const int &, const int &)>'无过载
- 传递给std::function template的template参数究竟代表什么
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 将函数包装器转换为 std::function
- 类型擦除的std::function与虚拟函数调用的开销
- C++ std::function 对于类 exept 的所有实例都是空的(只有 Visual2019 编译器问题)
- 如果模板没有可变参数,则 Lambda 被推导出为 std::function
- 将 lambda 表达式传递给 std::function in C++
- 模板类的部分模板专用化,如 std::function
- 可变参数模板参数扩展 类型为 std::function 的类成员
- 从 std::function in C++ 访问模板化 lambda
- 什么是 std::function::argument_type 的替代品?
- C++派生类重载函数(带有 std::function 参数)不可见
- 如何在 qi 符号表中使用 std::function
- 将 std::function 与模板一起使用
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数
- 我需要在 std::function 上使用 unique_ptr 吗?
- 如何将函数指针从 std::function 传递到 Linux 克隆?