adding a shared_ptr object on a weak_ptr container - boost

My class is based on boost::asio tutorial.
This class has a private ctor, is derived from enable_shared_from_this.
its static member function return a shared_ptr from the object created.
I want to store those pointers on a list of weak_ptr, so the list don't need to worry about its life time, either prolong it.
The caller tcp_serve instantiate tcp_connection with create method:
tcp_server:
tcp_connection::pointer new_connection =
tcp_connection::create(acceptor_.get_io_service());
tcp_connection:
PUBLIC:
typedef boost::shared_ptr<tcp_connection> pointer;
static pointer create(boost::asio::io_service& io_service)
{
return pointer(new tcp_connection(io_service));
}
PRIVATE:
tcp_connection(boost::asio::io_service& io_service)
: _socket(io_service), _timer(io_service)
{
}
I am trying to create a list on the tcp_server, I tried many different kind of types, but I can't rightly added the object to the list:
std::list<std::weak_ptr<tcp_connection>> connections;
connections.push_back(new_connection);

Related

Shared_ptr seems to work on copy, not on original object

I got 2 classes that represent Player and I want to keep in one of them pointer to another one.
So inside my view::Player I create pointer to logic::Player
namespace view {
class Player {
std::shared_ptr<logic::Player> m_player;
//logic::Player* m_player;
public:
void create(logic::Player& player) {
m_player = std::make_shared<logic::Player>(player);
//m_player = &player;
}
};
}
view::Player is created in view::GameState and simply initialised like this
m_playerOneView.create(m_game.getActivePlayer());
m_game is logic::Game object
logic::Game has std::vector<logic::Player>, and public method that returns active one
logic::Player& logic::Game::getActivePlayer() {
return m_players[m_activePlayer];
}
And finnaly
namespace logic {
class Player {
std::string m_name;
int position;
};
}
Now I need original object of logic::Player pointed by std::shared_ptr in my view::Player class. I could simply do that by changing that to raw pointer and it works then (2 commented lines do what I want to achieve basicly). But when I try to do this on std::shared_ptr, I seem to work on copy of logic::Player, because when I update his position for example, it changes everywhere in the game but not in view::Player. How to do that using std::shared_ptr then?

Wrapping std::map and provide pointer to element

I am using a library which offers a function foo(Widget*).
My Widgets are stored in
struct WidgetManager {
std::map<int, Widget> dict;
??? getWidget(int id);
}
Originally I stored (raw) Widget pointers in the std::map just because it was convenient to pass them to foo.
If I want to store the actual Widgets in the map, what should the return type of getWidget be so that I can pass a pointer of the Widget to foo?
I am compelled to make it of type iterator, but I don't like that I have to access itr->second to get the Widget(pointer).
You can use & just before you pass your widget to the foo(Widget*) function to get a pointer to it.
struct WidgetManager {
std::map<int, Widget> dict;
Widget& getWidget(int id);
}
usage
WidgetManager wm;
//...
Widget& w = wm.getWidget(id);
foo(&w);
//...

member function obtains copy of shared pointer to class instance

I am moving to using C++11 shared pointers.
I need to write member functions that adds pointers to the instance of their class to containers ( i.e. registers ( adds ) their presence in some collection )
Using plain old pointers, I can do this
class myClass {
public:
void Register( std::vector< myClass* >& v_registrants )
{
v_registrants.push_back( this );
}
};
But how to do the same when the collection holds shared pointers? Somehow the member function must obtain a copy of the shared pointer that owns the instance.
I cannot simply create a new shared pointer from this because:
If two shared_ptr are constructed (or made) from the same (non-shared_ptr) pointer, they will both be owning the pointer without sharing it, causing potential access problems when one of them releases it (deleting its managed object) and leaving the other pointing to an invalid location. ( reference )
So, what to do to implement the following class?
class myClass_safe {
public:
void Register( std::vector< std::shared_ptr<myClass_safe > >& v_registrants )
{
//v_registrants.push_back( this ); // compiler freaks out
}
};
As a workaround, I am doing this:
class myClass_safe {
public:
void Register(
std::shared_ptr<myClass_safe >& my_shared_ptr,
std::vector< std::shared_ptr<myClass_safe > >& v_registrants )
{
v_registrants.push_back( my_shared_ptr );
}
};
Which results in this rather strange code
// register the object
object->Register( object, v_registrants );
Is there not something better than this?
I believe this is exactly what std::enable_shared_from_this is intended for.
Inheriting from std::enable_shared_from_this<classname> provides your class with a member function called shared_from_this, that enables you to safely obtain a std::shared_ptr that shares ownership with the original owner.
So to use it, in your case, you would have to change your class definition like this:
class myClass_safe : public std::enable_shared_from_this<myClass_safe> {
public:
void Register( std::vector< std::shared_ptr<myClass_safe > >& v_registrants )
{
v_registrants.push_back( shared_from_this() );
}
};
Note also, that the object must be owned by a shared pointer prior to calling shared_from_this.

Single instance of an object

I'm trying to implement a singleton-like object with C++11. I got this example from another user.
It creates an object with the constructor and the copy constructor private and default, as well as an instance() function to return static object.
As I understand this should prevent the creation of two instances of this object. But as you can see in my main.cpp, I create two instances and it compiles and runs.
Is my object creation wrong or what? I don't get it.
object.hpp:
#ifndef OBJECT_H
#define OBJECT_H
#include <iostream>
using namespace std;
class Object
{
private:
Object() = default;
Object(const Object&) = delete;
public:
// Singleton in C++11
static Object& instance() { static Object z; return z; }
};
#endif // OBJECT_H
main.cpp:
#include "object.hpp"
int main()
{
Object* object = new Object();
object->instance();
Object* object2 = new Object();
object->instance();
return 0;
}
When I try to compile your code, I get a proper error from the compiler:
main.cpp: error: calling a private constructor of class 'Object'
Object* ob1= new Object() ;
So I would not be able to create two objects using new.
First your code in main won't compile. Object default constructor is private, so you won't be able to do :
Object* object = new Object();
Second, as instance() is static (means not related to any instance) there is no need to call it from an object, the class name suffices :
Object& theInstance = Object::instance();
Finally, the code of instance is :
static Object& instance()
{
static Object z;
return z;
}
It's OK. A static variable in a C++ function means that the object is instanciated once : when the function is ran for the first time. Then z won't be destroyed at the end of the function (contrary to other so-called local variables) and will be re-used for next calls of instance.
So at first call of instance :
z is created
z z is returned
At next calls :
z is returned
A singleton is a class which implies only one instance will be created. You can verify the objects are the same with :
Object& a = Object::instance();
Object& b = Object::instance();
std::cout << &a << std::endl;
std::cout << &b << std::endl;
a and b should have the same memory adress.
This is the expected behaviour of a singleton : if the object construction function (instance) is called several times, the same instance will be returned.
So as you said, instance actually prevents the creation of two Object. Maybe you expected you program to return some error on the second call of instance. If you wan't this behaviour, you'll have to make it yourself using expections or returning NULL. Yet, The code you wrote shows the classic way singletons are done in C++.

ptr_map and pointer

I'm using ptr_map from boost for storing objects derived from some base abstract type.
class Entity { virtual void foo() = 0; };
class Entity1 : public Entity {};
class Entity2 : public Entity {};
boost::ptr_map<string, Entity> someMap; // We could store pointers for abstract type
Inserting works great:
someMap.insert("someKey", new Entity1());
someMap.insert("someKey", new Entity2());
But not returning from map:
template<typename EntityType>
EntityType *GetEntity(const string &entityName)
{
return dynamic_cast<EntityType*>(&someMap[entityName]);
}
GetEntity<Entity1>(entityName);
Now the problem: operator[] of ptr_map returns reference! So in constructur there could be calling type from value.
Now compiler fails with error:
instantiated from ‘EntityType* EntityManager::GetEntity(const std::string&) [with EntityType = Entity1, std::string = std::basic_string<char>]’
error: cannot allocate an object of abstract type ‘Entity’
If there is any method in ptr_map which returns pointer to the value, there woudln't be any problems. What could you say about this?
An oft forgotten fact is that operator[] will instantiate the key if it doesn't exist. This is a problem in your case because the key is abstract.
So instead, use at().
That is,
return dynamic_cast<EntityType*>(&someMap.at(entityName));
For more info, read the "Semantics: lookup" section
BTW, I would question your design decision to expose raw pointers stored within container whose very purpose is to alleviate memory management.

Resources