【问题标题】:Using shared_ptr with a const reference将 shared_ptr 与 const 引用一起使用
【发布时间】:2017-06-30 23:06:16
【问题描述】:

我需要创建几个Worker 类,这些类具有指向主程序拥有的Object 的指针。这是在 C++14 中

出于某种原因,Object 必须满足某些条件 - 它必须有一个已删除的默认构造函数,它的不可复制、不可移动。我需要使用智能指针。

主程序将拥有Object。每个工人阶级都需要从中读取东西

class Object
{
  Object() = delete;
  ~Object();

  // Non copyable
  Object(const Object &other) = delete;
  Object &operator=(const Object &other) = delete;

  // Non movable
  Object(Object &&other) = delete;
  Object &operator=(Object &&other) = delete;

  // Constructor
  explicit Object(double threshold);
};

class Worker
{
public:
  void initialize(const Object& obj)
  {
    // Option 1 - errors out, complains its non copyable
    object_ptr = std::make_shared<const Object>(obj);

    // Option 2
    object_ptr = std::shared_ptr<const Object>(&obj);

    // Option 3
    object_ptr = std::shared_ptr<const Object>(&obj, [](const Object*){});
  }

  void doSomething();

private:
  std::shared_ptr<const Object> object_ptr;
};

int main () 
{
  Object object;

  Worker worker1;
  Worker worker2;

  worker1.initialize(object);
  worker2.initialize(object);

  while(1)
  {
    // Main does stuff to Object

    worker1.doSomething();
    worker2.doSomething();
  }

  return 0;
}

Worker 中初始化指针的最佳方法是什么?

【问题讨论】:

  • 是的,@DietrichEpp,shared_ptr 实际上不必保留共享引用。您可以使用别名构造函数来伪造它。你永远不应该,但你可以。
  • 如果工人不参与对象的所有权,为什么不让他们保留对对象的引用?如果您需要能够在构造工作程序后初始化引用(或需要能够更改引用),那么这可能是非智能原始指针的合法用例。否则,您似乎在无济于事地增加复杂性。
  • 您的模式似乎需要在主程序中使用 shared_ptr 并在您的工作人员中使用weak_ptr。如果需要智能指针,为什么要通过 const 引用传递对象?

标签: c++ c++14 shared-ptr


【解决方案1】:

我个人会这样做

class Worker
{
public:
    void initialize(const Object& obj)
    {
        object_ptr = &obj;
    }
private:
    const Object* object_ptr = nullptr;
};

原始指针表示非所有权,情况正是如此。

如果您必须使用shared_ptr,则无法将其作为参数传入,shared_ptr 与其关联的数据不仅仅是托管对象。

class Worker
{
public:
    void initialize(std::shared_ptr<const Object> p)
    {
        swap(object_ptr, p);
    }
private:
    std::shared_ptr<const Object> object_ptr;
};

int main()
{
    auto obj = std::make_shared<const Object>();
    //...
}

shared_ptr 的意思正是它所说的:资源是共享的。传递shared_ptr 就是声明有多个所有者,并且资源对所有人都是通用的,即资源必须比其中任何一个都长。

请注意您是如何将对象 在堆栈中(或者更确切地说,具有自动存储持续时间),这表明该资源实际上不属于工作人员。根据工人的定义,我们自动知道该对象将比工人更长寿,这远远优于使用shared_ptrs。

【讨论】:

    【解决方案2】:

    为什么不使用 shared_ptr 的aliasing constructor

    template< class Y > 
    shared_ptr( const shared_ptr<Y>& r, element_type* ptr ) noexcept; 
    

    这允许您创建一个 shared_ptr,但实际上并不拥有该对象,因此存储的值实际上不被引用计数。这意味着引用的对象必须在外部保持有效。

    在这种情况下,只需将初始化设置为:

    void initialize(const Object& obj)
      {
        typedef std::shared_ptr<const Object> my_ptr;
        object_ptr = my_ptr(my_ptr(), &obj);
      }
    

    这是一个 hack,它会伪造一个真正的 shared_ptr,但它会起作用。对于一个独立的外部示例,请尝试:

    #include <memory>
    
    struct x_t
    {
        x_t() = delete;
        x_t(const x_t&) = delete;
        x_t(x_t&&) = delete;
        x_t(double y) {}
    };
    
    int main()
    {
        typedef std::shared_ptr<const x_t> x_t_ptr;
        const x_t x(5);
    
        x_t_ptr ptr = x_t_ptr(x_t_ptr(), &x);
    
        return 0;
    }
    

    我真的应该警告你,你不应该这样做,因为当你没有这样的东西时,你似乎有记忆安全。基本上,您要保证您有内存安全,然后有效地使用指向临时对象的原始指针。这是非常危险的。

    【讨论】:

    • "这允许您创建一个 shared_ptr,但实际上并不拥有该对象" 不,不是,您认为这里的 别名 是什么是什么意思?
    • 因为它是一个指向它不拥有的对象的指针的别名?例如,在这里:codesynthesis.com/~boris/blog/2012/04/25/…
    • 我想我明白你为什么这么说。但是措辞非常具有误导性,如果您写的内容类似于您的链接所说的内容,就不会造成混淆
    • 它不拥有内存。它对对象的生命周期没有所有权。它不管理对象的生命周期。它不“拥有”对象,它指向它。它是一个原始指针的别名。这不是误导,是准确的。 @PasserBy
    • 不,它不准确,一方面,你没有提到它拥有另一个对象,也就是说,它正在管理另一个对象的生命周期。您也没有提到这种事情的主要用例是在指向其子对象时管理一个对象,该子对象间接拥有该子对象。你后来说用空的shared_ptr 别名是一种黑客攻击,这是完全正确的,但没有上述上下文就没有意义
    猜你喜欢
    • 2018-05-13
    • 2018-02-19
    • 1970-01-01
    • 2011-02-19
    • 1970-01-01
    • 1970-01-01
    • 2015-06-21
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多