473,396 Members | 1,783 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,396 software developers and data experts.

Deleting from destructor

mc
Hi Experts,

This may be obvious but I can't find anything one way or another. We have
a class which is always allocated using new, e.g. Foo* foo = new Foo() so we
came up with the idea of releasing the memory from the destructor as
follows:

Foo::Foo()
{
// Initialize stuff
m_This = this; // m_This is a "void*"
}

Foo::~Foo()
{
// Release all resources
// and finally the memory
delete m_This;
}

It's been working fine so far (both Windows and Linux) but we're wondering
about it being either the worse thing to do..... Any thoughts.

Thank you.

Regards,

MC
Oct 9 '08 #1
12 2325
mc wrote:
This may be obvious but I can't find anything one way or another. We have
a class which is always allocated using new, e.g. Foo* foo = new Foo() so we
came up with the idea of releasing the memory from the destructor as
follows:

Foo::Foo()
{
// Initialize stuff
m_This = this; // m_This is a "void*"
}

Foo::~Foo()
{
// Release all resources
// and finally the memory
delete m_This;
}

It's been working fine so far (both Windows and Linux) but we're wondering
about it being either the worse thing to do..... Any thoughts.
That is a VERY BAD IDEA. Basically, the only correct way to invoke the
destructor of an object that was created dynamically is to use 'delete'
with the expression evaluating to the pointer to that object. In most
cases if you have

Foo* foo = new Foo();

somewhere, then somewhere else you have

delete foo;

That will invoke the destructor and *then* deallocate the memory. Now,
if you duplicate the pointer somewhere (in the object itself, or in some
other place), and then use 'delete' with that pointer, you will be
*deleting* the object twice. I am not sure what 'delete (void*)ptr'
does (or does not) compared to 'delete ptr'. Most likely it can't call
the destructor since the type is unknown. But it will, and I am certain
of it, deallocate the memory.

So, if you do use 'delete' with your 'foo', you're deallocating the
memory twice, which is undefined behaviour. If you don't use 'delete
foo', then how do you get the destructor to be called? DO you call it
explicitly (foo->~Foo();)? Then it's rather nonsensical, you should
instead use the normal idiomatic way and let the system perform all the
necessary clean-up for you.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask
Oct 9 '08 #2
mc
Thanks Victor. I understand what you said and knew. Let me put more
context here but adding a more complete example:

void SKEL::bind(const MCU& mcu, ...)
{
// const FOO& MCU::foo()
// {
// return (*new Foo());
// }
FOO foo = mcu.foo(); // Because of the const FOO&
returned, foo becomes equal to what was returned by MCU::foo()

// do stuff
// when exising here, the destructor for FOO is called and the memory is
release as per previous post
}

The destructor for the object is only called once and no memory leaks were
detected.

MC

"Victor Bazarov" <v.********@comAcast.netwrote in message
news:gc**********@news.datemas.de...
mc wrote:
>This may be obvious but I can't find anything one way or another. We
have a class which is always allocated using new, e.g. Foo* foo = new
Foo() so we came up with the idea of releasing the memory from the
destructor as follows:

Foo::Foo()
{
// Initialize stuff
m_This = this; // m_This is a "void*"
}

Foo::~Foo()
{
// Release all resources
// and finally the memory
delete m_This;
}

It's been working fine so far (both Windows and Linux) but we're
wondering about it being either the worse thing to do..... Any thoughts.

That is a VERY BAD IDEA. Basically, the only correct way to invoke the
destructor of an object that was created dynamically is to use 'delete'
with the expression evaluating to the pointer to that object. In most
cases if you have

Foo* foo = new Foo();

somewhere, then somewhere else you have

delete foo;

That will invoke the destructor and *then* deallocate the memory. Now, if
you duplicate the pointer somewhere (in the object itself, or in some
other place), and then use 'delete' with that pointer, you will be
*deleting* the object twice. I am not sure what 'delete (void*)ptr' does
(or does not) compared to 'delete ptr'. Most likely it can't call the
destructor since the type is unknown. But it will, and I am certain of
it, deallocate the memory.

So, if you do use 'delete' with your 'foo', you're deallocating the memory
twice, which is undefined behaviour. If you don't use 'delete foo', then
how do you get the destructor to be called? DO you call it explicitly
(foo->~Foo();)? Then it's rather nonsensical, you should instead use the
normal idiomatic way and let the system perform all the necessary clean-up
for you.

V
--
Please remove capital 'A's when replying by e-mail
I do not respond to top-posted replies, please don't ask

Oct 9 '08 #3
mc wrote:
Thanks Victor. I understand what you said and knew. Let me put more
context here but adding a more complete example:

void SKEL::bind(const MCU& mcu, ...)
{
// const FOO& MCU::foo()
// {
// return (*new Foo());
// }
FOO foo = mcu.foo(); // Because of the const FOO&
returned, foo becomes equal to what was returned by MCU::foo()
Yes. It becomes a copy of it.
// do stuff
// when exising here, the destructor for FOO is called and the memory
is release as per previous post
The memory for the object foo in SKEL::bind is, but there is the other FOO
object that was dynamically allocated. It's still hanging around, and you
lost all pointers to it, so you can't ever deallocate it. That's a memory
leak. With the destructor you described, you also happen to use delete with
a pointer to memory you didn't get from new, which results in undefined
behavior.
}

The destructor for the object is only called once and no memory leaks were
detected.
Sounds like your memory debugger has a problem.

Oct 9 '08 #4
mc
I haven't lost the location where the object was; remember that in the
constructor a private member is initialized to the value of where the object
resides in memory; and the destructor uses a delete for that.
"Rolf Magnus" <ra******@t-online.dewrote in message
news:gc*************@news.t-online.com...
mc wrote:
>Thanks Victor. I understand what you said and knew. Let me put more
context here but adding a more complete example:

void SKEL::bind(const MCU& mcu, ...)
{
// const FOO& MCU::foo()
// {
// return (*new Foo());
// }
FOO foo = mcu.foo(); // Because of the const FOO&
returned, foo becomes equal to what was returned by MCU::foo()

Yes. It becomes a copy of it.
> // do stuff
// when exising here, the destructor for FOO is called and the memory
is release as per previous post

The memory for the object foo in SKEL::bind is, but there is the other FOO
object that was dynamically allocated. It's still hanging around, and you
lost all pointers to it, so you can't ever deallocate it. That's a memory
leak. With the destructor you described, you also happen to use delete
with
a pointer to memory you didn't get from new, which results in undefined
behavior.
>}

The destructor for the object is only called once and no memory leaks
were
detected.

Sounds like your memory debugger has a problem.

Oct 9 '08 #5
Please don't top-post.

mc wrote:
"Rolf Magnus" <ra******@t-online.dewrote in message
news:gc*************@news.t-online.com...
>mc wrote:
>>Thanks Victor. I understand what you said and knew. Let me put more
context here but adding a more complete example:

void SKEL::bind(const MCU& mcu, ...)
{
// const FOO& MCU::foo()
// {
// return (*new Foo());
// }
FOO foo = mcu.foo(); // Because of the const FOO&
returned, foo becomes equal to what was returned by MCU::foo()

Yes. It becomes a copy of it.
>> // do stuff
// when exising here, the destructor for FOO is called and the
memory is release as per previous post

The memory for the object foo in SKEL::bind is, but there is the other
FOO object that was dynamically allocated. It's still hanging around, and
you lost all pointers to it, so you can't ever deallocate it. That's a
memory leak. With the destructor you described, you also happen to use
delete with
a pointer to memory you didn't get from new, which results in undefined
behavior.

I haven't lost the location where the object was; remember that in the
constructor a private member is initialized to the value of where the
object resides in memory; and the destructor uses a delete for that.
Yes, you're right. I missed that. So the copy's destructor frees the
original object's memory. However, the original's destructor isn't properly
called as it's supposed to, which probably won't lead to problems in the
example you showed, but will in less trivial programs. This is very bad
style.


Oct 9 '08 #6
mc
Why is there a need for the original's destructor to be called? After all,
the original is copied verbatim and consequently the destructor is called
once as expected.

Be that as it may, this is indeed quite obfuscated. The reasoning for
that is that the main caller does not know the object is being allocated
using new and hence is not supposed to call delete. So we had to find a way
to free the memory used and went for a new in place (see actual code below):

const Region& MCU::buffer(void) const
{
char* p = new char[sizeof(Region)];
return (*new(p) Region(std::string(TEMP), 1500));
}

with the Region ctdt:

Region::Region(const std::string& name, size_t size)
{
_this = reinterpret_cast<char *>(this);
_cache = new unsigned char[size], _offset = 0;
_fd = ::open(name.c_str(), O_RDWR | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR
| S_IRGRP | S_IROTH);
assert(_fd != -1);
}
Output::Buffer::~Buffer()
{
if (_fd != -1)
{
::write(_fd, (char *)_cache, _offset);
::close(_fd);
}
delete[] _cache;
delete[] _this;
}

Does that make sense?


Oct 9 '08 #7
You did it again. Please do not top-post. It is frowned upon around these
parts.

mc wrote:
Why is there a need for the original's destructor to be called? After all,
the original is copied verbatim and consequently the destructor is called
once as expected.
[snip]

I am not sure, I understand your code. You have:

Foo::Foo() {
// Initialize stuff
m_This = this; // m_This is a "void*"
}

Foo::~Foo() {
// Release all resources
// and finally the memory
delete m_This;
}

const FOO& MCU::foo() {
return (*new Foo());
}

and then

FOO foo = mcu.foo(); // creates a copy

Now the destructor of the foo object will be called. This destructor, in
turn, is going to invoke

delete m_This;

which will call the destructor for the original. Here is what I do not
understand:

a) Why is m_This a void*? It appears that in this case

delete m_This;

will _not_ invoke the destructor of the original.

b) Why are you not running into an infinite loop? After all, the destructor
of the original, once invoked, has to execute

delete m_This;

too.

c) Could it be that (a) and (b) are related, i.e., do you run into an
infinite loop if m_This had type foo*? If that is the case, then with the

delete m_This;

statement in the destructor of the copy foo, you are likely invoking
undefined behavior because of a type mismatch of the actual object and what
you are telling the compiler [5.3.5/3].
Best

Kai-Uwe Bux
Oct 9 '08 #8
mc
Sorry for being opaque but I have no idea what top-posting is....
Oct 9 '08 #9
mc wrote:
Sorry for being opaque but I have no idea what top-posting is....

Ever heard of Google?

--
Ian Collins
Oct 9 '08 #10
mc wrote:
Sorry for being opaque but I have no idea what top-posting is....
<http://en.wikipedia.org/wiki/Top_posting>

See also:

<http://www.parashift.com/c++-faq-lite/how-to-post.html>


Brian
Oct 9 '08 #11
mc
"Default User" <de***********@yahoo.comwrote in message
news:6l************@mid.individual.net...
mc wrote:
>Sorry for being opaque but I have no idea what top-posting is....

<http://en.wikipedia.org/wiki/Top_posting>

See also:

<http://www.parashift.com/c++-faq-lite/how-to-post.html>


Brian
Thank you.
Oct 10 '08 #12
mc wrote:
Why is there a need for the original's destructor to be called?
For the otherwise empty object you have here, it might be ok (I don't know
if it's sanctioned by the standard), but when your object gets more members
that are themselves class instances, you will run into trouble.
After all, the original is copied verbatim and consequently the destructor
is called once as expected.
But you have two objects. One constructed by the default constructor, the
other constructed by the copy constructor. And each of those two objects is
supposed to be constructed once and destroyed once.
Be that as it may, this is indeed quite obfuscated. The reasoning for
that is that the main caller does not know the object is being allocated
using new and hence is not supposed to call delete.
Why do you have the dynamically allocated object at all? Just return by
value, and you get the same, but in a clean way.
So we had to find a way to free the memory used and went for a new in
place (see actual code below):

const Region& MCU::buffer(void) const
{
char* p = new char[sizeof(Region)];
return (*new(p) Region(std::string(TEMP), 1500));
}
Why not simply:

const Region MCU::buffer(void) const
{
return Region(std::string(TEMP), 1500);
}
Oct 11 '08 #13

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

2
by: Thomas Philips | last post by:
I'm teaching myself OOP using Michael Dawson's "Python Programming For The Absolute Beginner" and have a question about deleting objects. My game has two classes: Player and Alien, essentially...
6
by: Thomas Philips | last post by:
I have a question about deleting objects. My game has two classes, Player and Alien, essentially identical, instances of which can shoot at each other. Player is described below class...
15
by: Rick | last post by:
Hi, Does deleting an object more than one times incur undefined behavior? I think it doesn't but just making sure... thanks Rick
9
by: Aguilar, James | last post by:
Hey guys. A new question: I want to use an STL libarary to hold a bunch of objects I create. Actually, it will hold references to the objects, but that's beside the point, for the most part. ...
7
by: Rohit | last post by:
Iam writing an application that uses an abstract base class and a derived class that is implementation of the abstract base class. Say I have this piece of code: Derived *ptrToDerived=NULL;...
4
by: al havrilla | last post by:
hi all what does the phrase: "scalar deleting destructor" mean? i'm getting this in a debug error message using c++ 7.1 thanks Al
2
by: maynard | last post by:
I have defined a template class (tree data structure) that uses dynamic memory and has properly implemented ctor's, dtor and assignment operator. I can observe the address of my tree object prior...
3
by: Andy | last post by:
Hello, I have the following situation: Thread A is allocating a dataset, doing some low-level calculations and storing a pointer to the dataset in a std::list via push_back. Thread B should...
10
by: H.S. | last post by:
Hello, I have class in which I am allocating space for a double array in the constructor. I use the double array twice in one of the methods and then delete that array in the class's destructor....
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
0
by: emmanuelkatto | last post by:
Hi All, I am Emmanuel katto from Uganda. I want to ask what challenges you've faced while migrating a website to cloud. Please let me know. Thanks! Emmanuel
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...
0
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing,...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.