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 10 1853
<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 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 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 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
};
}; 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
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 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
"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
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
"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 This thread has been closed and replies have been disabled. Please start a new discussion. Similar topics
by: Dave |
last post by:
Hello all,
In the code below, I see the following output:
base::operator new(size_t, int)
base::base()
base::~base()
base::operator delete(void *)
In the case of an exception being thrown...
|
by: Nimmi Srivastav |
last post by:
There's a rather nondescript book called "Using Borland C++" by Lee
and Mark Atkinson (Que Corporation) which presents an excellent
discussion of overloaded new and delete operators. In fact there...
|
by: Nimmi Srivastav |
last post by:
There's a rather nondescript book called "Using Borland C++" by Lee
and Mark Atkinson (Que Corporation) which presents an excellent
discussion of overloaded new and delete operators.
I am...
|
by: Douglas Peterson |
last post by:
class Allocator
{
public:
virtual void * Alloc(size_t) = 0;
virtual void * Free(void*) = 0;
};
class Object
{
public:
|
by: Dave |
last post by:
Hello all,
I'd like to find a source on the web that discusses, in a comprehensive
manner and in one place, everything about new / delete. It should include
overloading operator new, the new...
|
by: silver360 |
last post by:
Hello,
I'm trying to create a basic Heap manager and i have some question
about new/delete overloading.
The following code give me this output :
>> $./heap
>> registered : 0x804d098
>>...
|
by: rohits123 |
last post by:
I have an overload delete operator as below
//////////////////////////////////
void operator delete(void* mem,int head_type) {
mmHead local_Head = CPRMemory::GetMemoryHead(head_type);...
|
by: jeffjohnson_alpha |
last post by:
We all know that a new-expression,
foo* a = new foo() ;
allocates memory for a single foo then calls foo::foo(). And we know
that
void* p = ::operator new(sizeof(foo)) ;
allocates a...
|
by: LuB |
last post by:
I am constantly creating and destroying a singular object used within
a class I wrote.
To save a bit of time, I am considering using 'placement new'. I guess
we could also debate this decision -...
|
by: =?Utf-8?B?R2Vvcmdl?= |
last post by:
Hello everyone,
I remembered delete is implemented through operator overloading, but I am
not quite clear.
Could anyone recommend some links about how delete is implemented so that
I can...
|
by: Charles Arthur |
last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
|
by: ryjfgjl |
last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
|
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
|
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...
|
by: nemocccc |
last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
|
by: marktang |
last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
|
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...
|
by: Oralloy |
last post by:
Hello folks,
I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>".
The problem is that using the GNU compilers,...
|
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...
| |