正确使用std :: unique_ptr和std :: weak_ptr

时间:2016-04-12 13:58:28

标签: c++ c++11 stl aggregation smart-pointers

在这种情况下,如何正确使用std::unique_ptrstd::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应该保留其原始指针吗?

3 个答案:

答案 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;
}