Skip to content

Commit

Permalink
turns out that shared_from_this() can not be called from the construc…
Browse files Browse the repository at this point in the history
…tor, so we made a special attach() function to postpone object initialization
  • Loading branch information
EmielBruijntjes committed Aug 20, 2014
1 parent 53b2bd9 commit d23e818
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 71 deletions.
6 changes: 5 additions & 1 deletion include/channel.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,11 @@ class Channel
* Construct a channel object
* @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
Expand Down
26 changes: 8 additions & 18 deletions include/channelimpl.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,11 @@ class ConsumedMessage;
class ChannelImpl : public Watchable, public std::enable_shared_from_this<ChannelImpl>
{
private:
/**
* The actual channel object
* @var Channel
*/
Channel *_parent;

/**
* Pointer to the connection
* @var ConnectionImpl
*/
ConnectionImpl *_connection;
ConnectionImpl *_connection = nullptr;

/**
* Callback when the channel is ready
Expand Down Expand Up @@ -74,7 +68,7 @@ class ChannelImpl : public Watchable, public std::enable_shared_from_this<Channe
* The channel number
* @var uint16_t
*/
uint16_t _id;
uint16_t _id = 0;

/**
* State of the channel object
Expand All @@ -84,7 +78,7 @@ class ChannelImpl : public Watchable, public std::enable_shared_from_this<Channe
state_connected,
state_closing,
state_closed
} _state = state_connected;
} _state = state_closed;

/**
* The frames that still need to be send out
Expand All @@ -109,11 +103,10 @@ class ChannelImpl : public Watchable, public std::enable_shared_from_this<Channe
ConsumedMessage *_message = nullptr;

/**
* Constructor to make a shared pointer
* @param parent the publis channel object
* @param connection pointer to the connection
* Attach the connection
* @param connection
*/
static std::shared_ptr<ChannelImpl> instantiate(Channel *parent, Connection *connection);
void attach(Connection *connection);

/**
* Push a deferred result
Expand All @@ -136,11 +129,8 @@ class ChannelImpl : public Watchable, public std::enable_shared_from_this<Channe
* Note that the constructor is private, and that the Channel class is
* a friend. By doing this we ensure that nobody can instantiate this
* 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:
/**
Expand All @@ -152,7 +142,7 @@ class ChannelImpl : public Watchable, public std::enable_shared_from_this<Channe
* Invalidate the channel
* This method is called when the connection is destructed
*/
void invalidate()
void detach()
{
_connection = nullptr;
}
Expand Down
70 changes: 19 additions & 51 deletions src/channelimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,49 +47,33 @@
namespace AMQP {

/**
* Derived class with public constructor
*
* We need this because std::make_shared<ChannelImpl> is not possible
* Destructor
*/
struct PublicChannelImpl : public ChannelImpl
ChannelImpl::~ChannelImpl()
{
/**
* Constructor
* @param parent
* @param connection
*/
PublicChannelImpl(Channel *parent, Connection *connection) : ChannelImpl(parent, connection) {}

/**
* Destructor
*/
virtual ~PublicChannelImpl() {}
};
// remove incoming message
if (_message) delete _message;
_message = nullptr;

/**
* 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);
// remove this channel from the connection (but not if the connection is already destructed)
if (_connection) _connection->remove(this);

// destruct deferred results
while (_oldestCallback) _oldestCallback.reset(_oldestCallback->next());
}

/**
* Construct a channel object
* @param parent
* Initialize the object with an connection
* @param connection
* @param handler
*/
ChannelImpl::ChannelImpl(Channel *parent, Connection *connection) :
_parent(parent),
_connection(&connection->_implementation)
void ChannelImpl::attach(Connection *connection)
{
// add the channel to the 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)
{
Expand All @@ -100,27 +84,11 @@ ChannelImpl::ChannelImpl(Channel *parent, Connection *connection) :
{
// busy connecting
_state = state_connected;

// valid id, send a channel open frame
send(ChannelOpenFrame(_id));
}
}

/**
* Destructor
*/
ChannelImpl::~ChannelImpl()
{
// remove incoming message
if (_message) delete _message;
_message = nullptr;

// remove this channel from the connection (but not if the connection is already destructed)
if (_connection) _connection->remove(this);

// destruct deferred results
while (_oldestCallback) _oldestCallback.reset(_oldestCallback->next());
}
}

/**
* Push a deferred result
Expand Down
2 changes: 1 addition & 1 deletion src/connectionimpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ ConnectionImpl::~ConnectionImpl()
close();

// 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();
}

/**
Expand Down

0 comments on commit d23e818

Please sign in to comment.