releaseing unmanaged STL objects

  • Thread starter Thread starter MuZZy
  • Start date Start date
M

MuZZy

HI,

Say i have a class(on C++) which has an unmanaged STL member of STRMAP which is a define for
map<string, string>.

class CL
{
public CL(){mp = new STRMAP()};
public void Dispose(delete mp);
STRMAP *mp; //unmamaged object
}

member affects how the class objectIs it enough to just "delete mp" to remove the stl object form
memory? Does having such an unmanaged wil be collected by GC?

Thank you,
Andrey
 
Since it's an unmanaged member, you will have to clean it up manually,
however I note that you don't use a finalizer. This means that if someone
dereferences your class without ever calling Dispose, you'll leak the map.
There was some huge argument on the perfect way to do this a while back, and
I can't recall if my way's good enough or not, but here you go:

ref class CL : IDisposable
{
public CL(){mp = new STRMAP()};

!CL() {
Dispose();
}
public void Dispose() {
delete mp;
SupressFinalize(this);
}

STRMAP *mp; //unmamaged object
}

I couldn't tell if you were using C++ Managed Extension, or C++/CLI from
your syntax, but it looked more C++/CLI to me, so that's the syntax I used.
 
Sean Hederman said:
Since it's an unmanaged member, you will have to clean it up manually,
however I note that you don't use a finalizer. This means that if someone
dereferences your class without ever calling Dispose, you'll leak the map.
There was some huge argument on the perfect way to do this a while back,
and I can't recall if my way's good enough or not, but here you go:

ref class CL : IDisposable
{
public CL(){mp = new STRMAP()};

!CL() {
Dispose();
}
public void Dispose() {
delete mp;
SupressFinalize(this);
}

STRMAP *mp; //unmamaged object
}

I couldn't tell if you were using C++ Managed Extension, or C++/CLI from
your syntax, but it looked more C++/CLI to me, so that's the syntax I
used.

IMO OP didn't say it was written using managed C++, the example you are
showing is based on the (unreleased) C++/CLI language revision, OP's
application is not written using C++/CLI (I suppose).

Willy.
 
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so just
in case, here's the managed extensions version (I hope..., I'm a bit rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}
 
MuZZy said:
HI,

Say i have a class(on C++) which has an unmanaged STL member of STRMAP
which is a define for map<string, string>.

class CL
{
public CL(){mp = new STRMAP()};
public void Dispose(delete mp);
STRMAP *mp; //unmamaged object
}

member affects how the class objectIs it enough to just "delete mp" to
remove the stl object form memory? Does having such an unmanaged wil be
collected by GC?

Thank you,
Andrey

No, Unmanaged memory is not collected by the GC, that is why it's unmanaged,
such classes must be freed by unmanaged code.
I assume this question relates to the other thread(s) you have posted
recently (Finalizer not running, memory leak, object size, profiler issue).
One question though, how are you passing the data from/to unmanaged code to
managed code? managed code cannot access STL data, so there must be some
marshaling being done, and there must exist a C++ non member function, that
gets called from managed code, that creates an instance of the unmanaged
class. And consequently, there must exist another non-member function that
gets called when you have to release the unmanaged class. The Dispose member
in above class cannot be called from C#, so I guess it's called by this
non-member function.

Without seeing some real code, and without a description of the GC and
managed memory usage pattern, there is little we can do to help you out.

Willy.
 
Sean Hederman said:
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so
just in case, here's the managed extensions version (I hope..., I'm a bit
rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}

Well there is no __gc and no ref, so to me it's native C++.
OP has posted to some other threads where he said it's unmanaged code
anyway.

Willy.

PS. Something like this maybe?

__gc class CL : public IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
~CL()
{
delete[] mp;
}

private:
STRMAP *mp; //unmamaged object
}
 
My, you are right. I read "unmanaged STL member" in the OP and just assumed
that the containing class would be managed. Doh!

Thanks for pointing out the errors, my C++ is very rusty. I try to keep
current with the syntax, but don't often use it.

Willy Denoyette said:
Sean Hederman said:
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so
just in case, here's the managed extensions version (I hope..., I'm a bit
rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}

Well there is no __gc and no ref, so to me it's native C++.
OP has posted to some other threads where he said it's unmanaged code
anyway.

Willy.

PS. Something like this maybe?

__gc class CL : public IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
~CL()
{
delete[] mp;
}

private:
STRMAP *mp; //unmamaged object
}
 
Willy said:
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so
just in case, here's the managed extensions version (I hope..., I'm a bit
rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}


Well there is no __gc and no ref, so to me it's native C++.
OP has posted to some other threads where he said it's unmanaged code
anyway.

Willy.

PS. Something like this maybe?

__gc class CL : public IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
~CL()
{
delete[] mp;
}

private:
STRMAP *mp; //unmamaged object
}


I'm realy sorry for confusing you guys - i was talking about managed C++.

SO here's the real sample:



// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}


// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET();
m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}


So do i free STL objects corectly?


Thank you
Andrey
 
Willy said:
No, Unmanaged memory is not collected by the GC, that is why it's unmanaged,
such classes must be freed by unmanaged code.
I assume this question relates to the other thread(s) you have posted
recently (Finalizer not running, memory leak, object size, profiler issue).
One question though, how are you passing the data from/to unmanaged code to
managed code? managed code cannot access STL data, so there must be some
marshaling being done, and there must exist a C++ non member function, that
gets called from managed code, that creates an instance of the unmanaged
class. And consequently, there must exist another non-member function that
gets called when you have to release the unmanaged class. The Dispose member
in above class cannot be called from C#, so I guess it's called by this
non-member function.

Without seeing some real code, and without a description of the GC and
managed memory usage pattern, there is little we can do to help you out.

Willy.


How can i free those classes from unmaanaged code if i only have managed?
Again, the managed C++ class has some unmanaged STL members.

Though, i'm more in c# and frankly lack knowledge with managed C++ so maybe my question is dumb - in
this case i'm sorry :) bu t could you please still help me?

Thank you,
Andrey
 
MuZZy said:
Willy said:
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so
just in case, here's the managed extensions version (I hope..., I'm a bit
rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}


Well there is no __gc and no ref, so to me it's native C++.
OP has posted to some other threads where he said it's unmanaged code
anyway.

Willy.

PS. Something like this maybe?

__gc class CL : public IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
~CL()
{
delete[] mp;
}

private:
STRMAP *mp; //unmamaged object
}


I'm realy sorry for confusing you guys - i was talking about managed C++.

SO here's the real sample:



// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}


// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET(); m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}


So do i free STL objects corectly?


Thank you
Andrey

Do you mean you were talking about managed C++ all the time in the other
threads as well, you are kidding,right?
Yes, you destroy the STRPAIRVECTOR, STRSET etc objects ( whatever they are)
like it should, but I would prefer you do this deterministically
(implementing IDisposable).
However I don't like what is following, what is Numbers and Num, where are
the coming from, are they members of this class?

Willy.
 
Willy said:
Willy said:
Looks like it to me, there's no __gc in front of class, and the access
modifiers are inline. Admittedly the OP also isn't using ref class, so
just in case, here's the managed extensions version (I hope..., I'm a bit
rusty)

__gc class CL : IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
virtual void Finalize(){
Dispose();
}

private:
STRMAP *mp; //unmamaged object
}



Well there is no __gc and no ref, so to me it's native C++.
OP has posted to some other threads where he said it's unmanaged code
anyway.

Willy.

PS. Something like this maybe?

__gc class CL : public IDisposable
{
public:
CL(){mp = new STRMAP()};

void Dispose() {
delete mp;
SupressFinalize(this);
}

protected:
~CL()
{
delete[] mp;
}

private:
STRMAP *mp; //unmamaged object
}


I'm realy sorry for confusing you guys - i was talking about managed C++.

SO here's the real sample:



// In .h file here is the part of class declaration
public __gc class CResSet : public DataSet
{
public:
CResSet(CResSet *rs);
~CResSet();
STRMAP *m_smTables;
STRPAIRVECTOR *m_vp;
STRSET *m_ssPopulated;
<...>
}


// In .cpp file, here is the finalizer releasing unmanaged memory

// constructor
TnrData::CResSet::CResSet()
{
<..>
m_vp = new STRPAIRVECTOR();
m_ssPopulated = new STRSET(); m_smTables = new STRMAP();
<..>
}

// finalizer
TnrData::CResSet::~CResSet()
{
delete m_smTables; // THESE ARE
delete m_vp; // UNMANAGED STL
delete m_ssPopulated; // OBJECTS

Counter--;
for (int i = 0 ; i < Numbers->Count; i++)
{
Object *o = Numbers->get_Item(i);
int iii = Convert::ToInt32(o);
if (iii == Num)
Numbers->Remove(o);
}
}


So do i free STL objects corectly?


Thank you
Andrey


Do you mean you were talking about managed C++ all the time in the other
threads as well, you are kidding,right?

Sorry, man :) I assumed that if the NG is about managed code (C#), then we would be talking about
managed C++ as well... My fault.
Yes, you destroy the STRPAIRVECTOR, STRSET etc objects ( whatever they are)
like it should, but I would prefer you do this deterministically
(implementing IDisposable).
Again I can only agree! But again, it's not possible in my case...
However I don't like what is following, what is Numbers and Num, where are
the coming from, are they members of this class?

"Numbers" is the static ArrayList object of this class, and "Num" is this class's object's int variable.
 
MuZZy said:
Sorry, man :) I assumed that if the NG is about managed code (C#), then we
would be talking about managed C++ as well... My fault.

*** No problem.
Again I can only agree! But again, it's not possible in my case...
*** There is no problem with this, as long as the size of these unmanaged
memory structures aren't too large there is no need to implement
IDisposable.
"Numbers" is the static ArrayList object of this class, and "Num" is this
class's object's int variable.
I don't know how large this ArrayList can be and how many of such AL you are
creating, but keep in mind that a static's lifetime is tied to it's
containing application domain, and that an ArrayList never shrinks. Assume
your AL holds 100000 object (boxed int's in your case) it will take 1.2MB of
managed memory that will stay in memory until the AD unloads.

Willy.
 
Willy said:
*** No problem.



*** There is no problem with this, as long as the size of these unmanaged
memory structures aren't too large there is no need to implement
IDisposable.

Those memory structures contain just some tables names and are mo big in size.
Also, most of them get finalized right after i call GC.WaitForPendingFinalizers().
I don't know how large this ArrayList can be and how many of such AL you are
creating, but keep in mind that a static's lifetime is tied to it's
containing application domain, and that an ArrayList never shrinks. Assume
your AL holds 100000 object (boxed int's in your case) it will take 1.2MB of
managed memory that will stay in memory until the AD unloads.

Thanks for your comment on this!

First, it's added only for debugging purpose - this static ArrayList as well as Num will not be
present in customer build. But anyway, we are experiencing memory losses of dozens of megabytes, so
one more MB wouldn't change the whole picture.

Andrey
 
Back
Top