turns out that shared_from_this() can not be called from the constructor, so we made a special attach() function to postpone object initialization

This commit is contained in:
Emiel Bruijntjes 2014-08-20 12:44:52 +02:00
parent 53b2bd9f0d
commit d23e818f64
4 changed files with 42 additions and 80 deletions

View File

@ -27,7 +27,11 @@ public:
* Construct a channel object * Construct a channel object
* @param connection * @param connection
*/ */
Channel(Connection *connection) : _implementation(ChannelImpl::instantiate(this, connection)) {} Channel(Connection *connection) : _implementation(new ChannelImpl())
{
// attach the connection to the channel
_implementation->attach(connection);
}
/** /**
* Destructor * Destructor

View File

@ -25,17 +25,11 @@ class ConsumedMessage;
class ChannelImpl : public Watchable, public std::enable_shared_from_this<ChannelImpl> class ChannelImpl : public Watchable, public std::enable_shared_from_this<ChannelImpl>
{ {
private: private:
/**
* The actual channel object
* @var Channel
*/
Channel *_parent;
/** /**
* Pointer to the connection * Pointer to the connection
* @var ConnectionImpl * @var ConnectionImpl
*/ */
ConnectionImpl *_connection; ConnectionImpl *_connection = nullptr;
/** /**
* Callback when the channel is ready * Callback when the channel is ready
@ -74,7 +68,7 @@ private:
* The channel number * The channel number
* @var uint16_t * @var uint16_t
*/ */
uint16_t _id; uint16_t _id = 0;
/** /**
* State of the channel object * State of the channel object
@ -84,7 +78,7 @@ private:
state_connected, state_connected,
state_closing, state_closing,
state_closed state_closed
} _state = state_connected; } _state = state_closed;
/** /**
* The frames that still need to be send out * The frames that still need to be send out
@ -109,11 +103,10 @@ private:
ConsumedMessage *_message = nullptr; ConsumedMessage *_message = nullptr;
/** /**
* Constructor to make a shared pointer * Attach the connection
* @param parent the publis channel object * @param connection
* @param connection pointer to the connection
*/ */
static std::shared_ptr<ChannelImpl> instantiate(Channel *parent, Connection *connection); void attach(Connection *connection);
/** /**
* Push a deferred result * Push a deferred result
@ -136,11 +129,8 @@ protected:
* Note that the constructor is private, and that the Channel class is * Note that the constructor is private, and that the Channel class is
* a friend. By doing this we ensure that nobody can instantiate this * a friend. By doing this we ensure that nobody can instantiate this
* object, and that it can thus only be used inside the library. * object, and that it can thus only be used inside the library.
*
* @param parent the public channel object
* @param connection pointer to the connection
*/ */
ChannelImpl(Channel *parent, Connection *connection); ChannelImpl() {}
public: public:
/** /**
@ -152,7 +142,7 @@ public:
* Invalidate the channel * Invalidate the channel
* This method is called when the connection is destructed * This method is called when the connection is destructed
*/ */
void invalidate() void detach()
{ {
_connection = nullptr; _connection = nullptr;
} }

View File

@ -46,66 +46,6 @@
*/ */
namespace AMQP { namespace AMQP {
/**
* Derived class with public constructor
*
* We need this because std::make_shared<ChannelImpl> is not possible
*/
struct PublicChannelImpl : public ChannelImpl
{
/**
* Constructor
* @param parent
* @param connection
*/
PublicChannelImpl(Channel *parent, Connection *connection) : ChannelImpl(parent, connection) {}
/**
* Destructor
*/
virtual ~PublicChannelImpl() {}
};
/**
* Constructor to make a shared pointer
* @param parent the publis channel object
* @param connection pointer to the connection
*/
std::shared_ptr<ChannelImpl> ChannelImpl::instantiate(Channel *parent, Connection *connection)
{
// we can only use std::make_shared with a PublicChannelImpl
return std::make_shared<PublicChannelImpl>(parent, connection);
}
/**
* Construct a channel object
* @param parent
* @param connection
* @param handler
*/
ChannelImpl::ChannelImpl(Channel *parent, Connection *connection) :
_parent(parent),
_connection(&connection->_implementation)
{
// add the channel to the connection
_id = _connection->add(shared_from_this());
// check if the id is valid
if (_id == 0)
{
// this is invalid
_state = state_closed;
}
else
{
// busy connecting
_state = state_connected;
// valid id, send a channel open frame
send(ChannelOpenFrame(_id));
}
}
/** /**
* Destructor * Destructor
*/ */
@ -122,6 +62,34 @@ ChannelImpl::~ChannelImpl()
while (_oldestCallback) _oldestCallback.reset(_oldestCallback->next()); while (_oldestCallback) _oldestCallback.reset(_oldestCallback->next());
} }
/**
* Initialize the object with an connection
* @param connection
*/
void ChannelImpl::attach(Connection *connection)
{
// get connection impl
_connection = &connection->_implementation;
// retrieve an ID
_id = _connection->add(shared_from_this());
// check if the id is valid
if (_id == 0)
{
// this is invalid
_state = state_closed;
}
else
{
// busy connecting
_state = state_connected;
// valid id, send a channel open frame
send(ChannelOpenFrame(_id));
}
}
/** /**
* Push a deferred result * Push a deferred result
* @param result The deferred object to push * @param result The deferred object to push

View File

@ -45,7 +45,7 @@ ConnectionImpl::~ConnectionImpl()
close(); close();
// invalidate all channels, so they will no longer call methods on this channel object // invalidate all channels, so they will no longer call methods on this channel object
for (auto iter = _channels.begin(); iter != _channels.end(); iter++) iter->second->invalidate(); for (auto iter = _channels.begin(); iter != _channels.end(); iter++) iter->second->detach();
} }
/** /**