Modify

Ticket #738 (closed Bugs: wontfix)

Opened 8 years ago

Last modified 10 months ago

Memory leaks with signal::connect?

Reported by: dgregor Owned by: dgregor
Milestone: Component: signals
Version: None Severity: Showstopper
Keywords: Cc:

Description (last modified by dgregor) (diff)

Hello,

I'm sending this message a second time (I didn't receive any response 
and still
have this problem)

I'm using boost::bind and boost::signal with VC6. VC6 is detecting 
some memory
leak for a certain type of signal.connect(). I've done a little test program 
to
check if the problem was due to some bug or special configuration in 
my main
program, but the memory leaks are still detected in the test situation.

Let me explain the structure of my test program. I have a main, and in 
the main,
an object CCloneAppRecipe named clone. The class CCloneAppRecipe 
contains a
member m_PtrTestMem (a shared pointer, but a raw point or an object 
does the
same thing) of the class CTestMem. CTestMem contains 3 instances of 
the class
CTestTab, and the class CTestTab contains a boost signal

typedef boost::signal0<void> TypeSignalTest;
TypeSignalTest m_SignalTest;

In my main, I invoke clone.connectPtrTestMem().
clone.connectPtrTestMem() then invokes
CTestMem::ConnectSignalTriplePtrTab(boost::bind
(&CloneAppRecipe::test, this));
ConnectSignalTriplePtrTab() then invokes ConnectSignal
(TypeSignalTest::slot_type
slot) for each of the 3 instances of the class it contains.
ConnectSignal then calls m_SignalTest.connect(slot).

And I have a memory leak: 2 blocks of 16 bytes. If I connect only one 
instance
of CTestTab, no leak. Two instances, one leak of 16 bytes. Three, two 
leaks of
16 bytes, and so on.

I connect the m_SignalTest with a CCloneAppRecipe's slot. If I connect 
it to a
CTestMem slot, I have no leak. Or if I place 3 instances of CTestTab 
directly
in the CCloneAppRecipe class (so I don't use CTestMem anymore), I 
have no leak.
But that's not what I need to do. I've tested plenty of variations
(shared_pointer or object, etc.) Does anybody have a clue.

Thanks


#include "stdafx.h"
#include "CloneAppRecipe.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



int main()
{
	CloneAppRecipe t;
	// cree un leak
	t.connectPtrTestMem();
	getchar();
	return 0;
}


void CloneAppRecipe::connectPtrTestMem()
{
	//m_ptrTestMem is a boost::shared_ptr
	m_ptrTestMem->ConnectSignalTriplePtrTab(boost::bind
(&CloneAppRecipe::test,
this));

}

void CloneAppRecipe::test() const
{
}

void CTestMem::ConnectSignalTriplePtrTab(const 
TypeSignaTest::slot_type&  slot)
{
	//m_ptrTestTab are boost::shared_ptr
	m_ptrTestTab1->ConnectSignal(slot);
	m_ptrTestTab2->ConnectSignal(slot);
	m_ptrTestTab3->ConnectSignal(slot);
}

void CTestTab::ConnectSignal(const TypeSignalTest::slot_type& slot)
{
	m_SignalTest->connect(slot);
}

CTestTab::~CTestTab()
{
	m_SignalTest->disconnect_all_slots();
}



here is my complete test program.

// TestMemBis.cpp : Defines the entry point for the console 
application.
//

#include "stdafx.h"
#include "CloneAppRecipe.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif



int main()
{
	CloneAppRecipe t;
	// cree un leak
	t.connectPtrTestMem();

	getchar();
	return 0;
}

// CloneAppRecipe.h: interface for the CloneAppRecipe class.
//
//////////////////////////////////////////////////////////////////
////

#if !defined(AFX_CLONEAPPREC__INCLUDED_)
#define AFX_CLONEAPPREC__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "TestMem.h"

class CloneAppRecipe
{
public:

	CloneAppRecipe();
	~CloneAppRecipe();


private:
	// desactive constructeur copie et operateur=
	CloneAppRecipe( const CloneAppRecipe& rhs );
	CloneAppRecipe& operator=( const CloneAppRecipe& rhs );

	// slot pour connecter
	void test() const;
public:
	void connectPtrTestMem();

	boost::shared_ptr<TestMem> m_ptrTestMem;

};

#endif

// CloneAppRecipe.cpp: implementation of the CloneAppRecipe class.
//
//////////////////////////////////////////////////////////////////
////


#include "stdafx.h"
#include "CloneAppRecipe.h"
#include "TestTab.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

CloneAppRecipe::CloneAppRecipe() : m_ptrTestMem( new TestMem() )
{
}

CloneAppRecipe::~CloneAppRecipe()
{
}

void CloneAppRecipe::test() const
{
}

void CloneAppRecipe::connectPtrTestMem()
{
	m_ptrTestMem->ConnectSignal(boost::bind
(&CloneAppRecipe::test, this));

}



// TestMem.h: interface for the TestMem class.
//
//////////////////////////////////////////////////////////////////
////

#if !defined(AFX_TESTMEM__INCLUDED_)
#define AFX_TESTMEM__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

class TestTab;

class TestMem
{
public:
	typedef boost::signal0<void> TypeSignalTest;

	TestMem();
	~TestMem();

	void ConnectSignal(const TypeSignalTest::slot_type&  slot) const;


private:
	// desactive constructeur copie et operateur=
	TestMem( const TestMem& rhs );
	TestMem& operator=( const TestMem& rhs );


	boost::shared_ptr<TestTab> m_ptrTestTab1;
	boost::shared_ptr<TestTab> m_ptrTestTab2;
	boost::shared_ptr<TestTab> m_ptrTestTab3;

};

#endif //
!defined
(AFX_VISIONPARAMTABMANAGER_H__F0F26B98_D7D0_489E_AD5F_0D
DEBF9A2D4F__INCLUDED_)

// TestMem.cpp: implementation of the TestMem class.
//
//////////////////////////////////////////////////////////////////
////


#include "stdafx.h"
#include "TestMem.h"
#include "TestTab.h"


#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

TestMem::TestMem()
:	m_ptrTestTab1( new TestTab() ),
	m_ptrTestTab2( new TestTab() ),
	m_ptrTestTab3( new TestTab() )
{
}

TestMem::~TestMem()
{

}


void TestMem::ConnectSignal(const TypeSignalTest::slot_type&  slot) 
const
{
	m_ptrTestTab1->ConnectSignal(slot);
	m_ptrTestTab2->ConnectSignal(slot);
	m_ptrTestTab3->ConnectSignal(slot);
}

// VisionParamGenericTab.h: interface for the CVisionParamGenericTab 
class.
//
//////////////////////////////////////////////////////////////////
////

#if !defined(AFX_TEST_TAB)
#define AFX_TEST_TAB

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000


typedef boost::signal0<void> TypeSignalTest;


class TestTab
{
public:

	TestTab();
	~TestTab();

	void ConnectSignal(const TypeSignalTest::slot_type& slot);

private:
    // desactive constructeur copie
	TestTab( const TestTab& rhs );
	TestTab& operator=( const TestTab& rhs );

	TypeSignalTest m_SignalTest;

};

#endif

// TestTab.cpp: implementation of the TestTab class.
//
//////////////////////////////////////////////////////////////////
////

#include "stdafx.h"
#include "TestTab.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif


TestTab::TestTab()
{

}

TestTab::~TestTab()
{
	m_SignalTest.disconnect_all_slots();
}

void TestTab::ConnectSignal(const TypeSignalTest::slot_type& slot)
{
	m_SignalTest.connect(slot);
}



// stdafx.h : include file for standard system include files,
//  or project specific include files that are used frequently, but
//      are changed infrequently
//

#if !defined
(AFX_STDAFX_H__4BC26E01_A411_43B7_9129_B453770CBE84__INCLU
DED_)
#define 
AFX_STDAFX_H__4BC26E01_A411_43B7_9129_B453770CBE84__INCLU
DED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#define WIN32_LEAN_AND_MEAN		// Exclude rarely-used stuff 
from Windows headers

#include <stdio.h>
#include <afx.h>
#include "CloneGeneral.h"
#include "BoostIInclude.h"


#endif //
!defined
(AFX_STDAFX_H__4BC26E01_A411_43B7_9129_B453770CBE84__INCLU
DED_)


CloneGeneral.h
#define 
AFX_GENERAL_H__F3520E35_333F_11D5_A855_000103C25D02__INCL
UDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

//#define for		if (1) for		// TODO_PASSAGE_6.0_8.0


#define BOOST_NO_INTRINSIC_WCHAR_T // requis parce que
BOOST_TT_AUX_BOOL_TRAIT_CV_SPEC1(is_integral,wchar_t,true)
								   // est défini 2 fois sinon et 
ca ne compile pas.

// disable auto-linking for Boost
#define	BOOST_ALL_NO_LIB

#endif //
!defined
(AFX_GENERAL_H__F3520E35_333F_11D5_A855_000103C25D02__INC
LUDED_)



BoostIInclude.h
#if !defined
(AFX_SVBOOSTBIND_H__F3520E35_333F_11D5_A855_000103C25D02_
_INCLUDED_)
#define 
AFX_SVBOOSTBIND_H__F3520E35_333F_11D5_A855_000103C25D02__
INCLUDED_

#pragma warning(push,1)
#include "boost/bind.hpp"
#include "boost/signal.hpp"
#include "boost/shared_ptr.hpp"
#pragma warning(pop)

#ifdef _DEBUG
    #pragma comment(lib, "libboost_signals-vc6-mt-gd.lib")
#else
    #pragma comment(lib, "libboost_signals-vc6-mt.lib")
#endif

#endif //
!defined
(AFX_SVBOOSTBIND_H__F3520E35_333F_11D5_A855_000103C25D02_
_INCLUDED_)


_______________________________________________
Boost-users mailing list
Boost-users@lists.boost.org
http://lists.boost.org/mailman/listinfo.cgi/boost-users

Attachments

test.cpp Download (498 bytes) - added by steven_watanabe 5 years ago.
Reduced test case

Change History

comment:1 Changed 7 years ago by marshall

  • Owner changed from dgregor to doug_gregor
  • Status changed from assigned to new
  • Severity set to Showstopper

Assigned to "doug_gregor" instead of nonexistent user "dgregor"

comment:2 Changed 6 years ago by dgregor

  • Owner changed from doug_gregor to dgregor
  • Description modified (diff)

Changed 5 years ago by steven_watanabe

Reduced test case

comment:3 Changed 5 years ago by steven_watanabe

The leak occurs as signal_base.cpp line 90 when attempting to insert a slot in more than one signal. The old pointer is overwritten and lost.

comment:4 Changed 5 years ago by steven_watanabe

The leak occurs at signal_base.cpp line 90 when attempting to insert a slot in more than one signal. The old pointer is overwritten and lost. I'm not sure whether this is supposed to work or not. The implementation of slot seems to assume that a slot will only be used in one signal, but the documentation doesn't seem to show such a restriction.

comment:5 Changed 10 months ago by viboes

Has this been fixed?

comment:6 Changed 10 months ago by marshall

  • Status changed from new to closed
  • Resolution changed from None to wontfix

Boost.Signals is being deprecated. Please transition to Boost.Signals2

View

Add a comment

Modify Ticket

Change Properties
<Author field>
Action
as closed
The resolution will be deleted. Next status will be 'reopened'
Author


E-mail address and user name can be saved in the Preferences.

 
Note: See TracTickets for help on using tickets.