在这种情况下,如何正确使用std::unique_ptr
和std::weak_ptr
?
struct B;
struct A
{
B* b;
float f;
A(float f, B* parent)
: f(f), b(parent)
{}
};
struct B
{
A a;
B(float f)
: a(f, this)
{}
};
我想用B
创建auto anB = std::unique_ptr<B>(new B(3.0f))
。我的猜测是A
应该有std::weak_ptr<B> b
而不是原始指针,但要创建std::weak_ptr
我需要std::shared_ptr
B
...
在这种情况下,A
应该保留其原始指针吗?
答案 0 :(得分:4)
所提供的信息不足以解决终身管理问题。
您提供了一些结构布局。你还没有描述如何使用结构中的数据,也没有描述它们的生命周期。
结构布局不会确定生命周期,除了理智的结构布局将是数据生命周期问题的函数。
你所做的就是说&#34;我有一些红色油漆,我想画一个房间。我应该买什么房子?&#34;结构布局对于解决寿命问题非常有用,而绘画对于在房屋中绘制房间非常有用,但提供结构布局并不能告诉您使用哪些智能指针,房屋涂料的颜色并不能告诉您买。
您需要考虑各种对象的生命周期,并尝试尽可能简单,然后使用智能指针,使管理变得容易。
答案 1 :(得分:2)
由于A
没有B
的所有权,因此原始(非拥有)指针是可以的。 (但其寿命应该长于A
)。
目前,您在使用默认复制构造函数/分配B / A时遇到问题,这可能会使A
指向旧B
。
对于weak_ptr
,确实B
应该放在shared_ptr
而不是unique_ptr
,并且为了允许相同的签名,它应该从std::enable_share_from_this
继承...
答案 2 :(得分:0)
从我们在评论中的对话中,我觉得分离问题可能是有序的。
A是B的属性。需要有一个B的规范存储(控制生命周期),并且需要有一个由B的某个属性排序的Bs的索引(非拥有)(在此案例,其中一个As)。
这支持两个向量(或一些其他适当的容器),一个包含Bs,另一个包含对Bs的有序引用。
您当然可以将容器和索引包装到另一个对象中以提供封装(我在下面的简单示例中没有这样做):
#include <vector>
#include <algorithm>
#include <memory>
#include <functional>
// define the attribute
struct A
{
float f;
A(float f)
: f(f)
{}
};
// define the object
struct B
{
A a1;
A a2;
// no back-pointers
B(float f, float f2)
: a1(f)
, a2(f2)
{}
};
int main()
{
using b_vec_type = std::vector<B>;
// build the canonical store
b_vec_type bs = { B { 1, 2}, B { 5, 4 }, B { 3, 4 } };
using a1_index_type = std::vector<std::reference_wrapper<B>>;
// build the index
a1_index_type index(bs.begin(), bs.end());
// sort the index by the attribute we want
std::sort(index.begin(), index.end(),
[](const B& l, const B& r) {
return l.a1.f < r.a1.f;
});
// now use the index:
for (const auto& e : index)
{
// do something with the Bs, ordered by B::a1
// e will be of type std::reference_wrapper<B>, which has
// a conversion operator to B& already defined.
}
return 0;
}