std::shared_ptr 以此构造
std::shared_ptr constructed from this
我想将 class 的所有对象添加到 std::map
。因为我不想复制对象,所以我尝试使用这样的智能指针来解决问题:
Class.h
class A : public std::enable_shared_from_this<A> {
public:
A();
~A();
static std::map<uint32_t, std::shared_ptr<A>> getObjects();
private:
static uint32_t counter;
uint32_t id;
static std::map<uint32_t, std::shared_ptr<A>> objects;
};
Class.cpp
A::A()
{
id = counter++;
std::shared_ptr<A> ptr = std::make_shared<A>();
objects[id] = ptr->shared_from_this();
}
A::~A()
{
objects.erase(id);
}
std::map<uint32_t, std::shared_ptr<A>> A::getObjects()
{
return objects;
}
uint32_t A::counter=0;
std::map<uint32_t, std::shared_ptr<A>> A::objects;
这编译得很好,但是当尝试像这样使用它时
int main(){
A a;
A b;
auto objects = A::getObjects();
}
我得到
Segmentation fault: 11`
如果我尝试将构造函数更改为
A::A()
{
id = counter++;
std::shared_ptr<A> ptr(this);
objects[id] = ptr->shared_from_this();
}
我得到
pointer being freed was not allocated
我基本上需要从 this
构造一个 std::shared_ptr<A>
但无法让它工作。
您无法获得指向不受共享指针管理的对象的拥有共享指针。
自动存储对象的生命周期可能没有由共享指针管理的生命周期。
一般来说,您的设计无法完成,因为对象和对象生命周期是由创建对象的代码控制的,而不是对象本身。
智能 pImpl 包装器可以使对象的内脏具有单独的智能指针确定的生命周期。但即使在那里,共享指针解决方案也是非法的,因为破坏地图会杀死最后一个共享指针,然后它会尝试重新输入地图代码并将其擦除。这是未定义的行为。
弱指针映射内容、基于 pImpl 的包装器、取消注册实例的智能删除器和其他工作的混合可能会起作用。这超出了 SO 答案的范围。
您必须了解如何管理对象生命周期、weak ptr 的工作原理、替代删除器、基于 pImpl 的值类型以及无数其他主题才能实现这一目标。祝你好运。
您的原始代码有堆栈溢出:
A::A()
{
id = counter++;
std::shared_ptr<A> ptr = std::make_shared<A>();
objects[id] = ptr->shared_from_this();
}
您在 A
的构造函数中无条件地构造了 A
。
您随后尝试的方法也不起作用:
A::A()
{
id = counter++;
std::shared_ptr<A> ptr(this);
objects[id] = ptr->shared_from_this();
}
shared_from_this()
仅当此对象的生命周期由 std::shared_ptr
.
管理时才有效
您可以选择几个选项。您 可以 使用静态工厂函数而不公开构造函数,但这对您的 class.
来说是一个意想不到的设计
对我来说更清晰的设计是做一些类似于 Pimpl 模式的事情。您可以将 std::shared_ptr
用于 A
的实际实现,并将功能包装在仅包含 shared_ptr
.
的对象中
如果你需要一个class的所有实例都存储在一个全局映射中,你可以试试这个:1)隐藏所有构造函数; 2) 仅通过静态 ('factory') 方法创建新对象。在您的情况下,此方法可以 return 一个 shared_ptr
(或者说,它可以 return 一个引用, shared_ptr 本身对全局地图是私有的;在这种情况下,您甚至可以使用 unique_ptr).
我想将 class 的所有对象添加到 std::map
。因为我不想复制对象,所以我尝试使用这样的智能指针来解决问题:
Class.h
class A : public std::enable_shared_from_this<A> {
public:
A();
~A();
static std::map<uint32_t, std::shared_ptr<A>> getObjects();
private:
static uint32_t counter;
uint32_t id;
static std::map<uint32_t, std::shared_ptr<A>> objects;
};
Class.cpp
A::A()
{
id = counter++;
std::shared_ptr<A> ptr = std::make_shared<A>();
objects[id] = ptr->shared_from_this();
}
A::~A()
{
objects.erase(id);
}
std::map<uint32_t, std::shared_ptr<A>> A::getObjects()
{
return objects;
}
uint32_t A::counter=0;
std::map<uint32_t, std::shared_ptr<A>> A::objects;
这编译得很好,但是当尝试像这样使用它时
int main(){
A a;
A b;
auto objects = A::getObjects();
}
我得到
Segmentation fault: 11`
如果我尝试将构造函数更改为
A::A()
{
id = counter++;
std::shared_ptr<A> ptr(this);
objects[id] = ptr->shared_from_this();
}
我得到
pointer being freed was not allocated
我基本上需要从 this
构造一个 std::shared_ptr<A>
但无法让它工作。
您无法获得指向不受共享指针管理的对象的拥有共享指针。
自动存储对象的生命周期可能没有由共享指针管理的生命周期。
一般来说,您的设计无法完成,因为对象和对象生命周期是由创建对象的代码控制的,而不是对象本身。
智能 pImpl 包装器可以使对象的内脏具有单独的智能指针确定的生命周期。但即使在那里,共享指针解决方案也是非法的,因为破坏地图会杀死最后一个共享指针,然后它会尝试重新输入地图代码并将其擦除。这是未定义的行为。
弱指针映射内容、基于 pImpl 的包装器、取消注册实例的智能删除器和其他工作的混合可能会起作用。这超出了 SO 答案的范围。
您必须了解如何管理对象生命周期、weak ptr 的工作原理、替代删除器、基于 pImpl 的值类型以及无数其他主题才能实现这一目标。祝你好运。
您的原始代码有堆栈溢出:
A::A() { id = counter++; std::shared_ptr<A> ptr = std::make_shared<A>(); objects[id] = ptr->shared_from_this(); }
您在 A
的构造函数中无条件地构造了 A
。
您随后尝试的方法也不起作用:
A::A() { id = counter++; std::shared_ptr<A> ptr(this); objects[id] = ptr->shared_from_this(); }
shared_from_this()
仅当此对象的生命周期由 std::shared_ptr
.
您可以选择几个选项。您 可以 使用静态工厂函数而不公开构造函数,但这对您的 class.
来说是一个意想不到的设计对我来说更清晰的设计是做一些类似于 Pimpl 模式的事情。您可以将 std::shared_ptr
用于 A
的实际实现,并将功能包装在仅包含 shared_ptr
.
如果你需要一个class的所有实例都存储在一个全局映射中,你可以试试这个:1)隐藏所有构造函数; 2) 仅通过静态 ('factory') 方法创建新对象。在您的情况下,此方法可以 return 一个 shared_ptr
(或者说,它可以 return 一个引用, shared_ptr 本身对全局地图是私有的;在这种情况下,您甚至可以使用 unique_ptr).