开发者

Can you set a weak_ptr<> in a ctor?

The following code fails to compile in Visual C++ 11 with this error:

1>c:\users\tony\documents\visual studio 11\projects\cpp11_ex1\cpp11_ex1\main.cpp(52): error C2440: '' : cannot convert from 'Foo *const ' to 'std::weak_ptr<_Ty>'

#include <stdio.h>
#include <memory>

using namespace std;

class Foo;

class Bar
{
public:
    Bar( weak_ptr<Foo> foo ) : _foo(foo) { printf("Bar(%p)\n",this); }
    ~Bar() { printf("~Bar(%p)\n",this); }
private:
    weak_ptr<Foo> _foo;
};

class Foo
{
public:
    Foo() : _bar() { _bar = make_shared<Bar>( weak_ptr<Foo>(this) );  printf("Foo(%p)\n",this); }
    ~Foo() { printf("~Foo(%p)\n",this); }
private:
    shared_ptr<Bar> _bar;
};

int main( int argc, char* argv[] )
{
    shared_ptr<Foo> instance = make_shared<Foo>();

    return 0;
}

It seems that I can't create a weak_ptr from a raw this pointer. This causes an interesting series of problems.

  1. Since I am attempting this in Foo's ctor, Foo's reference count is 0 (i.e. the make_shared<> in main hasn't retu开发者_Python百科rned yet).

  2. I've discovered that I can create weak_ptrs from shared_ptrs... But if I change Bar ctor to take a shared_ptr, I the act of calling Bar's constructor ends up destroying Foo! (Since Foo's reference count is still 0, creating (and then destroying) a shared_ptr to Foo via a call to Bar's ctor ).

All I really want to do is create Foo, have Foo create and own a Bar, but have Bar have a weak reference back to Foo. I really don't want to be forced into 2 part initialization here!


boost::weak_ptr<T> is for storing, not for using.

You want to pass boost::shared_ptr objects, and then store them in the boost::weak_ptr objects (usually private).

struct Foo {

  Foo(const boost::shared_ptr<int> &data) : weak_data(data) {}

  boost::shared_ptr<int> getData() {
    boost::shared_ptr<int> data = weak_data.lock();
    if (!data)
      throw std::runtime_error("data is no longer valid");
    return data;
  }

private:
  boost::weak_ptr<int> weak_data;

};

Whether you throw or pass back and empty shared_ptr<T> is up to you. If you cannot lock the object though, you shouldn't be passing it around anymore. It really isn't valid at that point.

That being said, you may want to refrain from creating a shared pointer in that manner. It isn't clear from your example if you need this design. If you can redesign it in a way like Mooing Duck suggested you will be better off, in all honesty.

From similar experiences when I needed circular dependencies like this, it probably is not a simple construction scenario. I would look at a two part constructor (static named constructor, or builder perhaps) to manage creating the two objects and ensuring that their references are valid.

Here is a quick example of a simple named constructor.

class Foo;

// Likely that this should be a child class of Foo
class Bar {
private:
  friend class Foo;
  Bar(const boost::shared_ptr<Foo> &foo) : weak_foo(foo) {}
  weak_ptr<Foo> weak_foo;
};

class Foo {
public:
  static boost::shared_ptr<Foo> CreateFoo() {
    boost::shared_ptr<Foo> foo = boost::shared_ptr<Foo>(new Foo);
    foo.bar = boost::make_shared<Bar>(foo);
    return foo;
  }

private:
  Foo() {}
  boost::shared_ptr<Bar> bar;
};

Here you control the invariant that your foo and bar variables are created correctly.


Since Foo will be pointed at by a shared_ptr, and Bar will always be owned by a shared_pointer of Bar, then if Bar exists, Foo exists. Ergo, you don't need a smart pointer in Bar. (If I understand the problem correctly)

#include <stdio.h>
#include <memory>

using namespace std;

class Foo;

class Bar
{
public:
    Bar( Foo* foo ) : _foo(foo) { printf("Bar(%p)\n",this); }
    ~Bar() { printf("~Bar(%p)\n",this); }
private:
    Foo* _foo;
};

class Foo
{
public:
    Foo() : _bar(new Bar(this)) { printf("Foo(%p)\n",this); }
    ~Foo() { printf("~Foo(%p)\n",this); }
private:
    shared_ptr<Bar> _bar;
};

int main( int argc, char* argv[] )
{
    shared_ptr<Foo> instance = make_shared<Foo>();
    return 0;
}


It is not possible to have a weak pointer in the absence of strong pointers to the same object, by definition. When the last strong pointer goes away, all the weak pointers turn null. That's all the weak pointers do.

Write your own function that returns a shared ptr to Foo (a Foo factory), and initialize the weak ptr in Bar from that pointer.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜