所以我一直致力于内存管理,并且在移动包含包含捕获数据的lambda的函数对象的对象时遇到了一个特殊问题。假设以下示例:
typedef std::function < void( int ) > funcType;
class Something
{
private:
int _myNum = 0;
public:
funcType GetSetIt( )
{
return [&] ( int a )
{
_myNum = a;
};
}
void SeeIt( )
{
std::cout << _myNum << std::endl;
}
int GetIt( )
{
return _myNum;
}
};
以下操作:
auto destination = ( Something* ) malloc( sizeof( Something ) );
auto alt = ( funcType* ) malloc( sizeof( funcType ) );
auto size = sizeof( funcType );
auto s = new Something( );
auto setIt = s->GetSetIt( );
setIt( 10 );
s->SeeIt( );
auto a = s->GetIt( );
memcpy( destination, s, sizeof( Something ) );
memset(s, 0, sizeof( Something ) );
memcpy( alt, &setIt, sizeof( funcType ) );
memset( &setIt, 0, sizeof( funcType ) ); // point 1
(*alt)( 15 );
destination->SeeIt( );
auto b = destination->GetIt( );
快速解释:
创建一个新的Something
并调用其所有成员以确保其正常运行。然后将其移动到新位置并删除/清除以前存在的位置。同时将函数对象移动到新位置并在之后清理。然后,使用指针指向新位置,调用函数对象和对象上的方法。
第一个问题是一切都在顺利进行,直到我memset
函数对象的原始位置。如果你注释掉那一行(用// point 1
标注),你会注意到它没有崩溃。
这对我来说有点奇怪,但我并不完全理解功能对象是如何在内存中布局的,并且希望在该区域有一些光线。我假设如果我将整个对象块复制到另一个区域并清除旧空间(不删除它,因为它在堆栈上),它将及其所有引用都将被保留。
第二个问题,假设您已注释掉memset
行,则“预期结果”与“预期结果”不同。我希望调用alt
会将_myNum
上的s
设置为15,确实如此。但我想更新alt
指向Something
的指针(我通常将其称为this
指针)指向destination
。我怎样才能做到这一点?它可以在编译器之间可靠地完成吗?我一直担心,虽然我可以想象它能够找到存储的位置并更新价值,但解决方案并不可靠,因为lambda可以在编译器之间以各种方式实现,并且可能存在一些“魔力”。
非常感谢您对这些问题的任何帮助或见解。如果我不清楚发生了什么,请评论,我会在需要的地方提供更多详细信息。提前谢谢!
答案 0 :(得分:3)
function
不可轻易复制(3.9p9,9p6),因此您无法使用memcpy
复制它。使用is_trivially_copyable
特征来检测类型是否可以轻易复制。
如果要将非平凡可复制类型的对象从一个位置“移动”到另一个位置,请使用placement new及其移动构造函数,并在之前的位置执行析构函数调用:
new (*buf) T(std::move(obj));
obj.~T();
答案 1 :(得分:0)
您应该使用placement new并确保从复制的对象中取出setter:
#include <functional>
#include <iostream>
// ...
int main() {
char source[sizeof(Something)];
char source_setter[sizeof(funcType)];
Something* src = new (source) Something;
// Get the setter from the source object.
funcType* src_setter = new (source_setter) funcType(src->GetSetIt());
(*src_setter)(0);
char destination[sizeof(Something)];
char destination_setter[sizeof(funcType)];
Something* dst = new (destination) Something(*src);
// Get the setter from the destination object.
funcType* dst_setter = new (destination_setter) funcType(dst->GetSetIt());
(*dst_setter)(1);
src->SeeIt();
dst->SeeIt();
src_setter->~funcType();
src->~Something();
dst_setter->~funcType();
dst->~Something();
}