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

Correct use of std::unique_ptr and std::weak_ptr

在这种情况下如何正确使用 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)
    {}
};

我想用 auto anB = std::unique_ptr<B>(new B(3.0f)) 创建一个 B。我的猜测是 A 应该有一个 std::weak_ptr<B> b 而不是原始指针,但是要创建 std::weak_ptr 我需要 std::shared_ptrB...
在这种情况下,A 应该只保留其原始指针吗?

由于 A 没有 B 的所有权,原始(非拥有)指针是可以的。 (但它的生命周期应该长于A)。

所以目前,B/A 的默认副本 constructor/assignment 有问题,这可能会使 A 指向旧的 B

对于weak_ptr,实际上,B应该放在shared_ptr而不是unique_ptr中,并且为了允许相同的签名,它应该继承自std::enable_share_from_this...

提供的信息不足以解决生命周期管理问题。

您提供了一些结构布局。您没有描述结构中的数据将如何使用,也没有描述它们的生命周期。

结构布局不决定生命周期,除了合理的结构布局将成为数据生命周期问题的函数。

你说了算"I have some red paint I want to paint a room with. What house should I buy?"结构布局对解决寿命问题很有用,油漆对房子粉刷房间很有用,但提供结构布局并没有告诉你用什么智能指针,而且房子油漆的颜色并不能告诉你买什么房子。

您需要考虑各种对象的生命周期,并尽量使其尽可能简单,然后然后使用智能指针进行管理简单。

从我们在评论中的谈话来看,在我看来,分离关注点可能是合适的。

A 是 B 的一个属性。需要有一个 Bs 的规范存储(控制生命周期)并且需要有一个 Bs 的索引(非拥有),该索引由 B 的某个属性排序(在这种情况下,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;
}