By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
445,655 Members | 962 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 445,655 IT Pros & Developers. It's quick & easy.

new and delete

P: n/a
Hi,
Below is a small code about memory allocation and deallocation.

#include <cstdlib>
#include <iostream>
using namespace std;

class X {
public:
void* operator new(size_t sz) throw (const char*) {
void* p = malloc(sz); //LINE1
if (p == 0) throw "malloc() failed";
return p;
}

void operator delete(void* p) {
free(p);
}

};

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl; //LINE2
free(p);
};

};

int main() {
X* ptr = new X; //LINE3

// call X::operator delete(void*)
delete ptr;

Y* yptr = new Y;

// call Y::operator delete(void*, size_t)
// with size of Y as second argument
delete yptr; //LINE4
}
My questions are:
When LINE3 is executed, LINE1 is executed. How is the variable sz
assigned sizeof(X)?

The output of the code is:
Freeing 400 byte(s)
When LINE4 is executed, LINE2 is executed. How does sz get the value
400?

Thanks a lot.

Jack

Jun 22 '06 #1
Share this Question
Share on Google+
10 Replies


P: n/a

<ju******@gmail.com> wrote in message
news:11**********************@r2g2000cwb.googlegro ups.com...
Hi,
Below is a small code about memory allocation and deallocation.

#include <cstdlib>
#include <iostream>
using namespace std;

class X {
public:
void* operator new(size_t sz) throw (const char*) {
void* p = malloc(sz); //LINE1
if (p == 0) throw "malloc() failed";
return p;
}

void operator delete(void* p) {
free(p);
}

};

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl; //LINE2
free(p);
};

};

int main() {
X* ptr = new X; //LINE3

// call X::operator delete(void*)
delete ptr;

Y* yptr = new Y;

// call Y::operator delete(void*, size_t)
// with size of Y as second argument
delete yptr; //LINE4
}
My questions are:
When LINE3 is executed, LINE1 is executed. How is the variable sz
assigned sizeof(X)?

The output of the code is:
Freeing 400 byte(s)
When LINE4 is executed, LINE2 is executed. How does sz get the value
400?


It's magic! :-)

Actually, the C++ standard doesn't specify how or where new and delete keep
this information stored. That's up to the people who wrote the compiler to
decide. Most likely, some code is executed "behind the scenes" which
determines the size of the object to be created, and stores it in a "hidden"
location, for use later when deleting. (I suppose you could try checking
the generated machine code and see exactly what it's doing.)

-Howard


Jun 22 '06 #2

P: n/a
ju******@gmail.com wrote:
Below is a small code about memory allocation and deallocation.

#include <cstdlib>
#include <iostream>
using namespace std;

class X {
public:
void* operator new(size_t sz) throw (const char*) {
void* p = malloc(sz); //LINE1
if (p == 0) throw "malloc() failed";
return p;
}

void operator delete(void* p) {
free(p);
}

};

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl; //LINE2
free(p);
};

};

int main() {
X* ptr = new X; //LINE3

// call X::operator delete(void*)
delete ptr;

Y* yptr = new Y;

// call Y::operator delete(void*, size_t)
// with size of Y as second argument
delete yptr; //LINE4
}
My questions are:
When LINE3 is executed, LINE1 is executed. How is the variable sz
assigned sizeof(X)?
Compiler magic.
The output of the code is:
Freeing 400 byte(s)
When LINE4 is executed, LINE2 is executed. How does sz get the value
400?


Compiler magic.

The 'operator new' and 'operator delete' are called by the executing
environment when you use the "new expression". There are intervening
mechanisms that know how much to pass to *your* 'new'.

Put a breakpoint in your 'operator new' and examine the call stack
under the debugger, when the execution is suspended. YOu will see
something between the 'main' and 'operator new', most likely. What
it is, isn't defined in the language. But it will be there.

You might find "Inside the C++ Object Model" by Lippman worth a look.

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

P: n/a
ju******@gmail.com wrote:
Hi,
Below is a small code about memory allocation and deallocation.

#include <cstdlib>
#include <iostream>
using namespace std;

class X {
public:
void* operator new(size_t sz) throw (const char*) {
void* p = malloc(sz); //LINE1
if (p == 0) throw "malloc() failed";
return p;
}

void operator delete(void* p) {
free(p);
}

};

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl; //LINE2
free(p);
};

};

int main() {
X* ptr = new X; //LINE3

// call X::operator delete(void*)
delete ptr;

Y* yptr = new Y;

// call Y::operator delete(void*, size_t)
// with size of Y as second argument
delete yptr; //LINE4
}
My questions are:
When LINE3 is executed, LINE1 is executed. How is the variable sz
assigned sizeof(X)?

The output of the code is:
Freeing 400 byte(s)
When LINE4 is executed, LINE2 is executed. How does sz get the value
400?

Thanks a lot.

Jack


A footnote to what Howard and Victor said: your class Y doesn't have a
custom new operator defined to match its delete operator. Consequently,
the default global new is used for creating your Y object, but the
object is deleted by your custom delete, which uses free(). This is
bad. See the FAQ:

http://www.parashift.com/c++-faq-lit....html#faq-16.3

See also _C++ Coding Standards_ by Sutter and Alexandrescu, Item 45.

Cheers! --M

Jun 22 '06 #4

P: n/a


A footnote to what Howard and Victor said: your class Y doesn't have a
custom new operator defined to match its delete operator. Consequently,
the default global new is used for creating your Y object, but the
object is deleted by your custom delete, which uses free(). This is
bad. See the FAQ:


Thanks. Now I free() by delete as the NEWLINE in the code below. Do you
think it is correct?

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::delete (Y*) p; //NEWLINE
};

};

Jun 22 '06 #5

P: n/a
ju******@gmail.com wrote:
...
Thanks. Now I free() by delete as the NEWLINE in the code below. Do you
think it is correct?

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::delete (Y*) p; //NEWLINE
};

};


No, this is not correct. In general case delete-expression does several
different things in sequence, one (and only one) of which is calling
your 'operator delete'. Here you inserted another delete-expression into
your 'operator delete's implementation. This will cause the whole
process to start all over again, which in general will lead to
unpredictable consequences. For example, the code will potentially make
an attempt to call the destructor of the object twice - first time from
the external delete-expression and second time from that
delete-expression you inserted into the 'operator delete'.

What you were trying to do in this case can be expressed correctly as
follows

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};

Note, that in this case instead of invoking another delete-expression,
we simply call the global 'operator delete' explicitly. I hope you
understand the difference between the two.

--
Best regards,
Andrey Tarasevich
Jun 22 '06 #6

P: n/a
Thanks.

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};

But it can not pass compiling. Below is the error:

new-delete.cc: In static member function `static void Y::operator
delete(void*,
unsigned int)':
new-delete.cc:31: error: invalid conversion from `size_t' to `void*'
new-delete.cc:31: error: initializing argument 2 of `void operator
delete(void*, void*)'

It seems to me that the compiler parses NEWLINE as Y::operator
delete(void*,
unsigned int).

When I change it into the code below, it works.
::operator delete(p); //NEWLINE

Is the second argument sz necessary? By the way, the global operator
delete does not invoke destructor, right?

Jack

Jun 22 '06 #7

P: n/a
ju******@gmail.com wrote:

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};
But it can not pass compiling. Below is the error:

new-delete.cc: In static member function `static void Y::operator
delete(void*,
unsigned int)':
new-delete.cc:31: error: invalid conversion from `size_t' to `void*'
new-delete.cc:31: error: initializing argument 2 of `void operator
delete(void*, void*)'

It seems to me that the compiler parses NEWLINE as Y::operator
delete(void*,
unsigned int).

When I change it into the code below, it works.
::operator delete(p); //NEWLINE

Is the second argument sz necessary?


You are right. The standard library does not provide global 'operator
delete' with size argument. That's why it doesn't compile. You can call
the '::operator delete(p)' instead.
By the way, the global operator
delete does not invoke destructor, right?


'operator delete' functions _never_ invoke destructors. These are raw
memory management functions. Delete-expressions call destructors,
'operator delete' fucntion don't. These are two different things. You
seem to be mixing the two.

--
Best regards,
Andrey Tarasevich
Jun 22 '06 #8

P: n/a

"Andrey Tarasevich" <an**************@hotmail.com> wrote in message
news:12*************@news.supernews.com...
ju******@gmail.com wrote:
...
Thanks. Now I free() by delete as the NEWLINE in the code below. Do you
think it is correct?

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::delete (Y*) p; //NEWLINE
};

};


No, this is not correct. In general case delete-expression does several
different things in sequence, one (and only one) of which is calling
your 'operator delete'. Here you inserted another delete-expression into
your 'operator delete's implementation. This will cause the whole
process to start all over again, which in general will lead to
unpredictable consequences. For example, the code will potentially make
an attempt to call the destructor of the object twice - first time from
the external delete-expression and second time from that
delete-expression you inserted into the 'operator delete'.

What you were trying to do in this case can be expressed correctly as
follows

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};

Note, that in this case instead of invoking another delete-expression,
we simply call the global 'operator delete' explicitly. I hope you
understand the difference between the two.


I thought the problem was that he's missing a new operator for the Y class.
Wouldn't the correct solution be to add that, not modify his delete
operator?

-Howard


Jun 22 '06 #9

P: n/a
Howard wrote:
...
What you were trying to do in this case can be expressed correctly as
follows

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};

Note, that in this case instead of invoking another delete-expression,
we simply call the global 'operator delete' explicitly. I hope you
understand the difference between the two.


I thought the problem was that he's missing a new operator for the Y class.
Wouldn't the correct solution be to add that, not modify his delete
operator?
...


Well, it depends on how you see it. I'd say that the actual problem was
that the memory deallocation function he used in his 'operator delete'
was potentially unrelated to the memory allocation function used by the
standard '::operator new'. Re-delegating the actual deallocation to the
standard '::operator delete' solved the problem.

Whether having a user-defined deallocation function without providing a
user-defined allocation function is a good style is a separate issue.

--
Best regards,
Andrey Tarasevich
Jun 22 '06 #10

P: n/a

"Andrey Tarasevich" <an**************@hotmail.com> wrote in message
news:12*************@news.supernews.com...
Howard wrote:
...
What you were trying to do in this case can be expressed correctly as
follows

class Y {
int filler[100];
public:

// two arguments
void operator delete(void* p, size_t sz) throw (const char*) {
cout << "Freeing " << sz << " byte(s)" << endl;
//free(p);
::operator delete(p, sz); //NEWLINE
};
};

Note, that in this case instead of invoking another delete-expression,
we simply call the global 'operator delete' explicitly. I hope you
understand the difference between the two.


I thought the problem was that he's missing a new operator for the Y
class.
Wouldn't the correct solution be to add that, not modify his delete
operator?
...


Well, it depends on how you see it. I'd say that the actual problem was
that the memory deallocation function he used in his 'operator delete'
was potentially unrelated to the memory allocation function used by the
standard '::operator new'. Re-delegating the actual deallocation to the
standard '::operator delete' solved the problem.

Whether having a user-defined deallocation function without providing a
user-defined allocation function is a good style is a separate issue.


Ah, ok. I thought maybe the operator new would be *required* in this case.
I keep learning...

Thanks, and regards,
-Howard

Jun 22 '06 #11

This discussion thread is closed

Replies have been disabled for this discussion.