Opened 10 years ago

Closed 10 years ago

#7724 closed Bugs (invalid)

executing signals2::signal::connect creates many copies of the connected object

Reported by: pszeptycki@… Owned by: Frank Mori Hess
Milestone: To Be Determined Component: signals2
Version: Boost 1.49.0 Severity: Problem
Keywords: signals2 connect multiple objects copy Cc:

Description

I am trying to figure out where is the problem, maybe what I have implemented is incorrect or it is a bug.

When trying to connect to a signal the passed object is copied many times and the final triggered signal executes a method on a copy of the passed object.

Signal is the following type:

typedef signals2::signal<void (NotificationCenter::Notification)> Signal;

Following code (NotificationCenter creates a shared_ptr<> to the requested signals):

class NotificationReceived
{
public:
	int runCount;
	NotificationReceived()
	{
		std::cout << "*  Receiver CREATED" << std::endl;
		runCount = 0;
	}

	NotificationReceived(const NotificationReceived &cSource)
	{
		std::cout << "*  Receiver COPIED" << std::endl;
		runCount = cSource.runCount;
	}

	~NotificationReceived()
	{
		std::cout << "*  Receiver DELETED" << std::endl;
	}

	void Receive(NotificationCenter::Notification notif) 
	{
		std::cout << std::endl << "Receive: Notification received: " + notif.m_information << std::endl << std::endl;
		runCount++;
	}
};

BOOST_AUTO_TEST_CASE( test_notification_center_notify)
{
	NotificationCenter nCenter(NotificationCenter::NCT_DELAYED);
	NotificationReceived receiver;
	NotificationCenter::Signal* sig = nCenter.RegisterForNotification(NotificationCenter::Notification::NT_BROADCAST);
	sig->connect(boost::bind(&NotificationReceived::Receive, receiver, _1));


	nCenter.BroadcastNotification(NotificationCenter::Notification(NotificationCenter::Notification::NT_BROADCAST, "Testing"));
	boost::this_thread::sleep(boost::posix_time::seconds(2));
	BOOST_REQUIRE_EQUAL(receiver.runCount, 1);
}

Has following output:

*  Receiver CREATED
- Queue empty - sleeping 500ms
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver DELETED
*  Receiver COPIED
*  Receiver DELETED
*  Receiver DELETED
- Thread waked up
- Queue not empty, searching receivers ...
- Sending notification

Receive: Notification received: Testing

- Queue empty - sleeping 500ms
- Thread waked up
- Queue empty - sleeping 500ms
- Thread waked up
- Queue empty - sleeping 500ms
*  Receiver DELETED
*  Receiver DELETED

*** 1 failure detected in test suite "FrameworkTests"

Why the "receiver" object has been copied many times and the final method has not been executed on the original object but on a copy which proves the check of the "runCount"?

I have managed to go around this problem adding a shared_ptr<>

Following code (classes the same):

	NotificationCenter nCenter(NotificationCenter::NCT_DELAYED);
	boost::shared_ptr<NotificationReceived> receiver(new NotificationReceived);
	NotificationCenter::Signal* sig = nCenter.RegisterForNotification(NotificationCenter::Notification::NT_BROADCAST);
	sig->connect(boost::bind(&NotificationReceived::Receive, receiver, _1));


	nCenter.BroadcastNotification(NotificationCenter::Notification(NotificationCenter::Notification::NT_BROADCAST, "Testing"));
	boost::this_thread::sleep(boost::posix_time::seconds(2));
	BOOST_REQUIRE_EQUAL(receiver->runCount, 1);

Outputs what I expected also from the first example:

*  Receiver CREATED
- Queue empty - sleeping 500ms
- Thread waked up
- Queue not empty, searching receivers ...
- Sending notification

Receive: Notification received: Testing

- Queue empty - sleeping 500ms
- Thread waked up
- Queue empty - sleeping 500ms
- Thread waked up
- Queue empty - sleeping 500ms
*  Receiver DELETED

*** No errors detected

Change History (1)

comment:1 by Frank Mori Hess, 10 years ago

Resolution: invalid
Status: newclosed

It's not a bug. Slots are copied by value, by design. If you want, you can submit a separate bug regarding the poor documentation of this fact.

Note: See TracTickets for help on using tickets.