为什么在更改范围时指向 boost 共享内存中的对象的指针会变得无效?

Why would a pointer to object in boost shared memory become invalid when changing scope?

TL;DR:为什么指向共享内存中对象的指针在简单更改范围后会变得无效?指针本身不在共享内存中。为什么它会变得毫无用处?


为了示例,假设我有一个简单的自定义数据类型:

class CustomDataType
{
public:
  short val;
  CustomDataType(short val__) { val = val__; };
  virtual ~CustomDataType() {};
  short square() { return val*val; };
};

我有一些函数在共享内存中创建此对象的实例并返回指向该对象的指针:

CustomDataType* someFunction()
{
  shared_memory_object::remove("Boost");
  managed_shared_memory managed_shm{ open_or_create, "Boost", 1024 };
  CustomDataType *i = managed_shm.construct<CustomDataType>("CustomDataTypeObject")(7);
  std::cout << i->square() << std::endl;
  return i;
}

我的 main 调用这个函数,然后尝试访问返回的指针:

void main()
{
  CustomDataType* customData = someFunction();
  std::cout << customData->square() << std::endl; // <------- program crashes
}

第一次通过函数内的指针调用方法 'square' 有效。

但是,第二次通过main中的指针调用方法'square'失败了。

为什么指针在范围更改后无法保存?我在同一个进程,对象还在内存中

一旦 managed_shared_memory 超出范围,指针是否会立即变得无用,即使它不会改变内存中的任何内容?

我是否遗漏了一些东西来使指针在范围更改后仍然存在?

我还尝试用 offset_ptr 替换标准指针,或者通过引用将指针传递给函数而不是返回它。没有任何内容修改代码的行为。

最小、完整且可验证的示例:

#include <boost/interprocess/managed_shared_memory.hpp>
#include <iostream>

using namespace boost::interprocess;

class CustomDataType
{
public:
  short val;
  CustomDataType(short val__) { val = val__; };
  virtual ~CustomDataType() {};
  short square() { return val*val; };
};

CustomDataType* someFunction()
{
  shared_memory_object::remove("Boost");
  managed_shared_memory managed_shm{ open_or_create, "Boost", 1024 };
  CustomDataType *i = managed_shm.construct<CustomDataType>("CustomDataTypeObject")(7);
  std::cout << i->square() << std::endl;
  return i;
}

void main()
{
  CustomDataType* customData = someFunction();
  std::cout << customData->square() << std::endl; // <------- program crashes
}

问题是当共享内存管理对象managed_shm超出作用域时,它被销毁,共享内存被分离(所以指向它的所有指针都变得无效)。

通常,您将全局变量用于共享内存管理对象,因此共享内存映射在程序完成之前一直有效(除非明确销毁)。

来自the documentation

When the managed_shared_memory object is destroyed, the shared memory object is automatically unmapped, and all the resources are freed.

这意味着当 managed_shm 超出范围时,您 return 的指针 i 变为悬空。