Jump to content

  • Log In with Google      Sign In   
  • Create Account

We're offering banner ads on our site from just $5!

1. Details HERE. 2. GDNet+ Subscriptions HERE. 3. Ad upload HERE.


Don't forget to read Tuesday's email newsletter for your chance to win a free copy of Construct 2!


Question on boost::shared_ptr


Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.

  • You cannot reply to this topic
15 replies to this topic

#1 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 01 November 2012 - 08:36 AM

Hi,

I'm a beginner about boost.
And i try to write some code like:

#include "stdafx.h"
#include <boost/shared_ptr.hpp>
class A;
class B;
class A
{
public:
A() {};
boost::shared_ptr<B> a;
boost::shared_ptr<B> b;
};
class B
{
public:
B(){};
boost::shared_ptr<A> a;
boost::shared_ptr<A> b;
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B b;
a.a=boost::shared_ptr<B>(&b);
a.b=boost::shared_ptr<B>(&b);
b.a=boost::shared_ptr<A>(&a);
b.b=boost::shared_ptr<A>(&a);
return 0;
}

This program is crash.
Who can tell me what's happend?

Edited by blackfe2010, 01 November 2012 - 08:37 AM.


Sponsor:

#2 Faelenor   Members   -  Reputation: 396

Like
2Likes
Like

Posted 01 November 2012 - 08:49 AM

You should only use shared_ptr for dynamically allocated objects (allocated with new)! You are passing the address of objects created on the stack, that's why it crashes.

#3 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 01 November 2012 - 09:19 AM

Hi
It works, thx.

And how to convert "this" pointer to shared_ptr?

Edited by blackfe2010, 01 November 2012 - 09:20 AM.


#4 Faelenor   Members   -  Reputation: 396

Like
0Likes
Like

Posted 01 November 2012 - 09:31 AM

I think you shouldn't, but can you give me an example of what you would like to do?

#5 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 01 November 2012 - 09:37 AM

I want do something like this:
class Manager
{
public:
  void addComponent(boost::shared_ptr<Component> comp)
  {
    comp->m_Manager=this;
  }
};
class Component
{
public
  boost::shared_ptr<Manager> m_Manager;
};
But how to let it work?

#6 SiCrane   Moderators   -  Reputation: 9628

Like
2Likes
Like

Posted 01 November 2012 - 09:38 AM

To that derive your class from boost::enable_shared_from_this and call shared_from_this().

#7 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 01 November 2012 - 09:43 AM

oh~, thx. it works very well.

#8 rip-off   Moderators   -  Reputation: 8517

Like
3Likes
Like

Posted 01 November 2012 - 12:48 PM

For completeness:
  • Because shared_ptr<> takes "ownership" of the passed pointer, it is incorrect to create two shared_ptr<>s from the same raw pointer
  • It is incorrect to create cyclical loops via shared_ptr (at least if you actually want to prevent memory leaks). The relationship would need to be parent/child, with the child holding a non-shared pointer (e.g. a weak_ptr<> or possibly a raw pointer if you are confident) to the parent.


#9 joew   Crossbones+   -  Reputation: 3676

Like
2Likes
Like

Posted 01 November 2012 - 01:05 PM

Note that if you create multiple shared pointers to the same raw pointer (as noted above never to do) they will each hold their own reference count therefore deleting before the other is out of scope. That is what you should always construct shared pointers with either shared_from_this() in the class or make_shared() elsewhere.

#10 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 01 November 2012 - 05:46 PM

For completeness:

  • Because shared_ptr<> takes "ownership" of the passed pointer, it is incorrect to create two shared_ptr<>s from the same raw pointer
  • It is incorrect to create cyclical loops via shared_ptr (at least if you actually want to prevent memory leaks). The relationship would need to be parent/child, with the child holding a non-shared pointer (e.g. a weak_ptr<> or possibly a raw pointer if you are confident) to the parent.

So you means two or more shared_ptr can not point to the same raw pointer?
But i found some description about shared_ptr like "Object ownership shared among multiple pointers."
How to understand it?

And actually, I want do something like:
class Object
{
public:
  void addComponents(boost::shared_ptr<Component> comp)
  {
	m_components.push_back(comp);
  }

  vector< boost::shared_ptr<Componnet> > m_components;
};
class ObjectManager : public boost::enable_shared_from_this<ObjectManager>
{
public:
  void addComponent(boost::shared_ptr<Component> comp)
  {
    comp->m_Manager=shared_from_this();
	m_allComponents.push_back(comp);
	m_allObjects[some_id].addComponents(comp);
  }

  vector< boost::shared_ptr<Component> >m_allComponents;
  vector< boost::shared_ptr<Object> > m_allObjects;
};
class Component
{
public
  boost::shared_ptr<ObjectManager> m_Manager;
};

Some Components in Object::m_components are point the same Component in ObjectManager::m_allcomponents.
So it is incorrect?

Edited by blackfe2010, 01 November 2012 - 05:54 PM.


#11 rip-off   Moderators   -  Reputation: 8517

Like
2Likes
Like

Posted 02 November 2012 - 03:26 AM

So you means two or more shared_ptr can not point to the same raw pointer?

Two shared pointers can share the same object. However, the way to do this is to create one shared_ptr<> to the object, and then copy the shared_ptr<>:
Example *example = new Example();
boost::shared_ptr<Example> one(example);
boost::shared_ptr<Example> two = one;
Under the hood, this means that both shared_ptrs are aware of one another and the reference count of the object will be 2.

If you wite code like this:
Example *example = new Example();
boost::shared_ptr<Example> one(example);
boost::shared_ptr<Example> two(example);
Then each shared_ptr assumes that it has exclusive ownership of the object. There will be two reference counts, both set to 1. When "one" goes out of scope, it will delete the object (provided no additional shared_ptr instances are created from it). Now two is left with a dangling pointer, and when it goes out of scope it will attempt to delete an invalid pointer.

And actually, I want do something like ... So it is incorrect?

You appear to have a circular reference, so none of these shared_ptr instances will ever be destroyed. While you can break the cycle using weak_ptr<> or a raw pointer, I would advise you to also consider alternative designs that are less coupled to one another. For example, why does the Component class need to talk to the "Object Manager"? I would question the necessity of an "Object Manager" class.

#12 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 02 November 2012 - 08:24 AM

why does the Component class need to talk to the "Object Manager"? I would question the necessity of an "Object Manager" class.


Because i want Component can communicate to other Components
class Component
{
public:
  void sendMessage(string str)
  {
	m_objectManager->sendGlobalMessage(str);
  }
};
class ObjectManager
{
pubic:
  void sendGlobalMessage(string str)
  {
	  for_each(m_allComponents.begin(),m_allComponents.end(),...);
  }
};

And about the weak_ptr<>, you means i should do something like:
class Component
{
  boost::weak_ptr<ObjectManager> m_ojbectManager;
};
right?
but weak_ptr haven't operator -> how can i use it?

Edited by blackfe2010, 02 November 2012 - 08:38 AM.


#13 joew   Crossbones+   -  Reputation: 3676

Like
1Likes
Like

Posted 02 November 2012 - 08:41 AM

You have to lock a weak pointer which turns it into a shared pointer for the duration of the scope. For example std::shared_ptr<ObjectManager> manager = m_objectManager.lock();

#14 Servant of the Lord   Crossbones+   -  Reputation: 20348

Like
2Likes
Like

Posted 02 November 2012 - 10:18 AM

I want do something like this:

class Manager
{
public:
  void addComponent(boost::shared_ptr<Component> comp)
  {
	comp->m_Manager=this;
  }
};
class Component
{
public
  boost::shared_ptr<Manager> m_Manager;
};


In such circumstances, since 'Component' does not "own" (unique_ptr) or "share ownership" (shared_ptr) of the lifetime of Manager, Component should use a raw pointer. Raw pointers are not evil. Smart pointers don't replace raw pointers in every circumstance, only the circumstances where the pointer needs to manage the lifetime of the memory. In your example, you are just accessing the memory.

If it is possible for Manager to be destructed before the components are destructed, then you should use a weak_ptr (if Manager is managed by a smart_ptr) - otherwise, if Manager's lifetime is guaranteed to exceed every Component lifetime, raw pointer is the proper solution. When adding the new tool "smart pointer" to your toolbox, you don't discard the previous tool "raw pointer", even if 90% of the old tool's duty is now taken over by the new tool. You don't throw away your screwdrivers when you buy a drill - there are many situations where a screwdriver is superior. Posted Image
(I have owned many a drill and many a screwdriver and frequently use them both - different tools for different jobs, even if their potential usage overlap 90% of the time)

class Manager
{
public:
  void addComponent(boost::shared_ptr<Component> comp)
  {
	comp->m_Manager = this;
  }
};
class Component
{
private:
	 friend class Manager;
	 Manager* m_Manager;
};

shared_ptr is (most likely) the proper choice for Manager's tracking of the Components (I'm assuming Manager has a vector of shared_ptr<Component>?). However, why unnecessarily copy the shared_ptr? Pass it to addComponent as a const ref.
void addComponent(const boost::shared_ptr<Component> &comp)
{
	 this->components.push_back(comp);
	 this->components.back()->m_Manager = this;
}

Further, typedefs are awesome.
class Component
{
	 //I use wPtr for 'weak pointer', uPtr for 'unique ptr', and I personally use 'Ptr' for shared_ptr, but sPtr would also be good.
	 //I don't typedef raw pointers, as the asterisk itself identifies it better than any single letter could: Component *ptr;
	 typedef boost::shared_ptr<Component> sPtr;
};

Component::sPtr mySharedPtr;

Furtherly further, one of the main points of smart pointers is that you don't need to handle the destruction of your data. A common rule of C++, is "Never new without delete", "never new[] without delete[]", "never malloc() without free()", etc...

Using smart pointers, while yes, technically you are new-ing and delete-ing properly, more accurately, you are new-ing, and the smart pointer is delete-ing. It'd be better (though not required), if you let smart pointers do the new-ing and delete-ing for you, so that a single API handles it entirely for the sake of consistency.

Enter boost::make_shared. More typing, but logically better as you ensure there is no chance for you to possibly mishandle the memory.
boost::make_shared() new()s the data, and returns it already in a shared_ptr, so you don't accidentally make the two deadly mistakes (both which you already made in this thread):
1) Passing stack data to a shared_ptr, mistakenly telling shared_ptr is is solely responsible for deleting the data (which isn't true, the stack would delete it)
2) Passing dynamic memory to two separate shared_ptrs. mistakenly telling each shared_ptr individually and separately that it is solely responsible for deleting the data (which isn't true, they both are responsible, but you accidentally told them they they were solely responsible).

Both avoided if you hold yourself to a single simple rule: Always use make_shared() to create your shared_ptrs. Posted Image
Component::sPtr mySharedPtr = boost::make_shared<Component>(/* Component's constructor arguments can go here, as if this was a normal constructor */);

std::unique_ptr = I own this object, nobody else owns it _or_ uses it.
std::shared_ptr = I own this object, possibly with shared ownership (through other std::shared_ptrs), and possibly with shared use (through weak_ptrs).
std::weak_ptr = I don't own this object, I just use it.
Regular raw pointer '*' = I don't own this object, I just use it (only use if the pointer's lifetime is guaranteed to be longer than the class containing it)

(The smart pointers in boost are probably in std::tr1:: namespace if you are not using C++11, or in std:: namespace if you are using C++11. They are basically the same, though they may have some minor changes. Boost is often a testing ground for new C++ Standard Library features)

weak_ptr can only be created from shared_ptrs. Weak pointers to memory not managed by a shared_ptr would basically be a raw pointer anyway (talking about high level, not implementation details), if it was allowed - which thankfully it isn't.

Enabling shared_from_this, is most likely not the correct thing you want to be using here (but it's hard to tell from only a small portion of code).
Using weak_ptrs to the Manager is also most likely the wrong choice.

Raw pointers are not evil, and this is one of the situations where they are the better solution.

Edited by Servant of the Lord, 02 November 2012 - 10:27 AM.

It's perfectly fine to abbreviate my username to 'Servant' rather than copy+pasting it all the time.
All glory be to the Man at the right hand... On David's throne the King will reign, and the Government will rest upon His shoulders. All the earth will see the salvation of God.
Of Stranger Flames - [indie turn-based rpg set in a para-historical French colony] | Indie RPG development journal

[Fly with me on Twitter] [Google+] [My broken website]

[Need web hosting? I personally like A Small Orange]


#15 rip-off   Moderators   -  Reputation: 8517

Like
3Likes
Like

Posted 02 November 2012 - 12:43 PM

make_shared() has another advantage, it allows the implementation to do a single allocation for the object data and the reference counting data, rather than having two allocations.

#16 blackfe2010   Members   -  Reputation: 150

Like
0Likes
Like

Posted 03 November 2012 - 03:06 AM

Thank you for your help!!!

I think it's clear for me.




Old topic!
Guest, the last post of this topic is over 60 days old and at this point you may not reply in this topic. If you wish to continue this conversation start a new topic.



PARTNERS