0

I have two classes, for instance, A and B. I would like to pass A as reference to B.

class I
{
public:
    virtual void callback() = 0;
};

class B
{
public:
    B(I* callback) : _callback(callback) {}
private:
    I* _callback;
};

class A : public I
{
public:
    A() : _b(new B(this)) {}
private:
    B* _b;
};

And I would like to:

  1. get rid of naked pointers (for instance, with a help of std::shared_ptr and std::weak_ptr).
  2. avoid cyclic referencing.

But there are some problems:

  1. How do I create a weak pointer INSIDE a class A? First, I should be sure that an instance of A is managed by some shared_ptr. Even if I'm really sure, how can I find this shared_ptr instance?
  2. Generally, how can I ensure that I'm using instances of some class ONLY via shared pointers? I can try to create factory method and make constructor private, but it leads to error: make_shared demands a public contstructor.

Thanks in advance!

EDIT:

More detail explanation of problem: I have a class A. This class wants to pass some part of work to a class B. So I have a shared pointer to B inside A. And I would like B to do this asynchronously, and B should call A's callback when there is some progress or when the work is done. So B should have a reference to A.

class I
{
public:
    virtual void isDone() = 0;
};

class B
{
public:
    B(I* callback) : _callback(callback) //how do I take and store callback inside B???
    {
        //async invocation of run()
    }
private:
    weak_ptr<I> _callback;

    void run()
    {
        if(_callback.get())
        {
            _callback->isDone();
        }
    }
};

class A : public I
{
public:
    A() : _b(new B(this)) {} //how do I pass this to B???
private:
    shared_ptr<B> _b;

    virtual void isDone()
    {
        cout << "job is complete" << '\n';
    }
};

So the question is: how do I pass A to B? I can try to do it via naked pointer or reference, but it's safety because B has no guarantees that this referenced object is still alive (common problem of all naked pointers). So I would like to pass a weak pointer, and my question was all about it.

slashdot
  • 630
  • 5
  • 14
  • Don't see any `std::weak_ptr` in your sample?? – πάντα ῥεῖ Feb 07 '14 at 20:38
  • @πάνταῥεῖ this example is an origin of problem. To use a weak pointer properly is an essence of the question :). – slashdot Feb 07 '14 at 20:50
  • Usually it helps for SO questions, to show what you have tried, and why it didn't work. – πάντα ῥεῖ Feb 07 '14 at 20:53
  • I'd use a full shared pointer in this case, not a weak pointer. Use a weak_ptr if you want to allow the object to go out of scope and then handle that situation, but in this case you *don't* want the object to go out of scope. Since you are already using the shared pointer, it doesn't add any overhead to use more instances of the shared pointer. – IdeaHat Feb 07 '14 at 20:54
  • @MadScienceDreams but what about cyclic referencing? If A have a shared pointer to B and B have shared pointer to A? – slashdot Feb 07 '14 at 21:06
  • In general, I avoid that situation like the plague :-P. I've found (in most cases) that if B needs a reference to A (and only A) and A needs B (and only B), that A~=B...in the cases you must have the cyclic reference, then yeah, you'd be stuck with the weak pointer. – IdeaHat Feb 07 '14 at 21:13
  • Smart pointers are all about ownership. We can't realistically suggest how to best use smart pointers in your code without you describing the ownership semantics. For example, looking at the code I would assume that this is the PIMPL pattern: `A` owns the `B` pointed at by `b_`, meaning the the lifetime of `b_` is strictly constrained within the lifetime of the associated `A`. I would suggest that you use a `std::unique_ptr` for `b_` and an `I&` for `_callback`. But it would be better if you described the problem instead of leaving it to us to guess. – Casey Feb 07 '14 at 21:46

1 Answers1

2

The first problem can be solved with std::enable_shared_from_this, which allows you to safely create a shared pointer instance from within class A.

The second problem may be solved by using a static factory method belonging to class A and not using std::make_shared like this:

static std::shared_ptr<A> create() {
    return std::shared_ptr<A>(new A());
}

Then, you can make A's constructor private.

Kristian Duske
  • 1,769
  • 9
  • 14
  • Thank you very much, Kristian! One more question: what is a common practice for passing a weak pointer to other class? Where should I create a weak pointer: inside A (before passing) or inside B (after passing)? – slashdot Feb 07 '14 at 20:46
  • I usually do it in B. I never pass weak ptrs around. Although there's something to be said for documenting ownership semantics in the method signatures. – Kristian Duske Feb 07 '14 at 20:52
  • (+1, though you should mention that the factory method could belong to another friend class, cuz factory pattern yay) – IdeaHat Feb 07 '14 at 20:53