[...]
I build my own class. I don't need to use vector because I don't need
all the features such as search or insert element / remove element. I
suppose to put an assignment operator and a copy constructor to
private if I don't need to use them.
So? The question is: do you need some feature std::vector doesn't
provide, or is it important to ban some feature that it does provide
(as
opposed to just not using it)? If not, just use std::vector. And if
you do need to ban some feature (often wise), then you'll still use
std::vector in the implementation of your class.
For example:
class array
{
public:
array( int size )
{
m_pArray = new int[ size ];
m_size = size;
if( m_pArray == 0 )
{
// Display Error Message -- out of memory
// Close other application and try again or
// use exit() function
This behaviour is better delegated into the new_handler function.
That you should set a new_handler (function std::set_new_handler), and
output the message and exit from it. Until you really know what you
are
doing, this is probably the best solution. (Even after you know what
you are doing, it's often the best solution.)
Note that even this may be trickier than it seems, since trying to
output a message may try to allocate dynamic memory. One solution
I've
frequently seen used is to pre-allocate a reserve buffer, which is
freed
first thing in the new handler. Alternatively, you can use setbuf on
std::cerr, or you can use system level output requests and static
buffers. (The latter solution is the most robust, but is not
portable.)
I create some classes to build different objects and put them into
memory. For example, 5 different classes are constructed successfully
and are stored in memory. They will be destructed after the program
exits successfully. If one class attempts to allocate more memory,
then bad allocation must be returned before new_handler exception is
thrown. Correct?
No. If you use a normal new (not placement) expression and don't
worry
about it. The basic algorithm of the operator new function is
required
to be:
void* result = attempt_to_allocate_memory();
while ( result == NULL )
{
(*current_new_handler)();
result = attempt_to_allocate_memory();
}
// Post-condition of loop: result != NULL !!!
return result;
The default new handler throws std::bad_alloc, but you can set it to
just about anything you want: the requirements are that it must do one
of three things:
-- make more memory available and return
-- throw std::bad_alloc or an exception derived from std::bad_alloc
-- exit the program (exit() or abort()).
(It may do more, e.g. log the fact that an error has occured, or
restore
the default new handler if it can't free up memory, for example.)
I do not need to test to find out if new keyword returns a pointer
with bad allocation.
A new expression always returns a valid pointer. If it returns.
I should use new_handler instead, but I have to use test condition to
find out if a is already allocated.
// Are ready to terminate your program.
// I have to clean up to deallocate memory.
It's perfectly acceptable to "abort" a program without cleaning up
memory. Except in special cases, there are really only two
alternatives
for handling out of memory: set the new handler to terminate the
program, or catch std::bad_alloc at the highest level and exit with an
error message. (The latter may be preferable if e.g. the program uses
temporary files which will be deleted in destructors.) In either
case,
treat out of memory as a fatal error.
If a is the result of a new expression, you can always delete it. If
a
is a null pointer, you can delete it as well. And if a is something
else, there's absolutely no way to test for it, so your program logic
must ensure that it's one of those. And you don't need the if, ever.
Please explain why you dislike hungarian notation.
Because it makes the code unmaintainable (and unreadable).
It provides you more information when you need to know because there
may be hundreds or thosuands of variables.
In one class? Thousands of member variables sounds like a design
error
to me.
More generally, while there may be any number of variables in the
entire
function, you should never deal with more than a few at a time. And
usually, whether a variable is an int or a long is less important than
whether it is an x coordinate, a color id, or a timestamp (and if it's
a
pointer, that will be immediately evident in the way it is used).
There's a reasonable argument for Hungarian as it was originally
designed (where information as to whether the variable was an
x-coordinate, a color-id or a timestamp was encoded), although even in
such cases, I find it better to avoid unpronounciable abbreviations,
and
in production code, at least, to define class types for each type,
rather than using int or long. (This is a perfect example of what I
mentionned at the start: banning some functionality. You don't want
to
support adding a timestamp to an x-coordinate, for example, but if
both
are int's, you do support it. And if you support subtraction of
timestamps, the result shouldn't be a timestamp, but an interval. So
you write a class, which uses int in its implementation, but only
supports the operations you want.)
[...]
Here is another good example.
#include <iostream>
using std::cerr;
using std::cout;
using std::endl;
#include <new>
using std::set_new_handler;
#include <cstdlib>
using std::abort;
using std::exit;
class array
{
public:
array( int size ) : m_size( size ), m_pLargeArray( new long long
[ size ] )
{
cout << "array::constructor -- count: " << ++s_ObjectCount << endl;
}
~array()
{
cout << "array::destructor -- count: " << s_ObjectCount-- << endl;
delete [] m_pLargeArray;
}
private:
long long *m_pLargeArray;
int m_size;
Why not simple
static int s_ObjectCount;
};
int array::s_ObjectCount = 0;
void customNewHandler()
{
cerr << "customNewHandler was called.\n";
cerr << "Display Error: Not enough Memory.\n\n";
cerr << "Your C++ project must be terminated." << endl;
// abort();
exit( EXIT_SUCCESS );
EXIT_SUCCESS?
int main()
{
set_new_handler( customNewHandler );
array a1( 50000000 ); // Success
array a2( 50000000 ); // Success
array a3( 50000000 ); // Success
array a4( 50000000 ); // Success
array a5( 50000000 ); // Failed -- bad memory allocation.
cout << "C++ project runs successful." << endl;
If bad memory allocation is detected, then will exit() function does
its own responsibility to deallocate a1, a2, a3, and a4 from the
memory before program is terminated?
Once the program ceases to exist, it doesn't have any resources.
Unless
something is persistent (files, etc.), in a very real sense, it ceases
to exist. (This may not be true in a freestanding implementation.)
Once exit() is finished, your process doesn't exist, and has no memory
to be freed. (Physically, of course, the memory chips are still in
the
computer, and the OS will reuse them for something else. Just as it
will also clean up any more abstract resources your process was using:
file locks, mutex or semaphores, etc.)
Do you suggest me to put new_handler exception in main.cpp only?
If you're using a new handler, you should set it first thing in main.
(or even before, but that's somewhat trickier).