简体   繁体   中英

Using shared_ptr with a const reference

I need to make several Worker classes that have a pointer to an Object owned by the main program. This is in C++14

For reasons, the Object has to meet certain criteria - it has to have a deleted default constructor, its non-copyable, non-movable. And I need to use smart pointers.

The main program will own the Object . Each worker class needs to read stuff from it

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

What's the best way to initialize the pointer inside of Worker ?

I personally would do this

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

A raw pointer indicates non-ownership, which is exactly what the situation is.

If you must use a shared_ptr , there is no way around passing in one as an argument, shared_ptr has more data associated with it than just the managed object.

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>();
    //...
}

A shared_ptr means exactly what it says: the resource is shared . To pass around a shared_ptr is to proclaim there are multiple owners and the resource is common to all of them, aka the resource must outlive any of them.

Note how you have the object on the stack (or rather, have automatic storage duration) which is indicative that this resource is not in fact, owned by the workers. By definition of the workers, we know automatically that the object will outlive the workers, and this is by far superior to using shared_ptr s.

Why not use shared_ptr's aliasing constructor .

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

This allows you to create a shared_ptr, but not actually own the object, so the stored value is not actually reference counted. This means the referenced object must remain valid externally.

In this case, just set initialize to be:

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

It's a hack, and it will fake a true shared_ptr, but it will work. For a self-contained, external example, try:

#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;
}

I should really warn you that you should not do this, since you will appear to have memory safety when you have no such thing. Basically, you're making a guarantee that you have memory safety, while then effectively using a raw pointer to a temporary object. This is very dangerous.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM