memory leak in the code?


G

George2

Hello everyone,


Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
    a = new int [N];
    b = new int [M];
} catch (bad_alloc)
{
    // if a success, but b fail, should we try to delete[] a here to
avoid memory leak?

}


thanks in advance,
George
 
Ad

Advertisements

E

Erik Wikström

Hello everyone,


Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
a = new int [N];
b = new int [M];
} catch (bad_alloc)
{
// if a success, but b fail, should we try to delete[] a here to
avoid memory leak?

}

Yes, but what about if you get a bad_alloc when allocating a? Then you
will try to delete whatever memory that the garbage in a points to. To
prevent this use something like this instead:

try {
int* a = 0;
a = new int[N];
int* b = new int[N];
}
catch (bad_alloc)
{
delete[] a;
}

Or use some kind of smart pointer, in which case you do not need to try-
block since the pointers will free any memory if the exception is thrown.

auto_ptr<int> a = new int[N];
auto_ptr<int> b = new int[N];

Note also that depending on what type of application you are writing it
might be useless to catch bad_alloc (except for diagnostic purposes)
since it can be quite hard to recover from. In all applications I have
written a bad_alloc is a terminal failure.
 
A

Andrew Koenig

Yes, but what about if you get a bad_alloc when allocating a? Then you
will try to delete whatever memory that the garbage in a points to. To
prevent this use something like this instead:

try {
int* a = 0;
a = new int[N];
int* b = new int[N];
}
catch (bad_alloc)
{
delete[] a;
}

Well, the idea is right but the implementation is wrong, because a will be
out of scope in the delete statement. Moreover, unless a and b are deleted
inside the try, the code will leak memory if it succeeds, because once a and
b are out of scope, there's no further opportunity to delete the memory.

An alternative:

int* a = 0;
try {
a = new int[N];
int* b = new int[N];

// do additional work here

delete[] b;
delete[] a;
} catch (bad_alloc) {
delete[] a;
}

I agree with you that smart pointers are the way to go here :)
 
S

Salt_Peter

Hello everyone,

Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
a = new int [N];
b = new int [M];} catch (bad_alloc)

{
// if a success, but b fail, should we try to delete[] a here to
avoid memory leak?
[/QUOTE]

I have doubts, so lets find out, Mr Holmes:

#include <iostream>
#include <stdexcept>

class A
{
  static int count;
public:
  A()
  {
    std::cout << "A()\n";
    if(2 == count)
      throw std::bad_alloc();
    count++;
  }
  ~A() { std::cout << "~A()\n"; }
};

int A::count;

class B
{
public:
  B() { std::cout << "B()\n"; }
  ~B() { std::cout << "~B()\n"; }
};

int main()
{
  A* p_a = 0;
  B* p_b = 0;
  try {
    p_b = new B[5];
    p_a = new A[5];
  } catch (const std::bad_alloc& e)
  {
    std::cout << "error: ";
    std::cout << e.what() << std::endl;
  }
}

/*
B()
B()
B()
B()
B() // obviously, something is wrong
A()
A()
A()
~A()
~A()
error: St9bad_alloc
*/

So we definitely have a problem.
Is the solution to delete [] p_a?
no. thats the wrong solution, there is a simpler, better way.
A std::vector own its elements unless these are pointers.
also, a std::vector invokes copy construction to populate elements at
creation time.
So to track what is happening, we need to modify A's copy ctor to
increment a static counter.

....
#include <vector>

class A
{
  static int copy_count;
  static int count;
public:
  ...
  // A's copy ctor
  A::A( const A& copy)
  {
    std::cout << "copy A\n";
    if(2 == copy_count)
      throw std::bad_alloc();
    copy_count++;
  }
  ...
};

int A::count;
int A::copy_count;

int main()
{
  try
  {
    std::vector< B > vb(5);
    std::vector< A > va(5);
  }
  catch (const std::bad_alloc& e)
  {
    std::cout << "error: ";
    std::cout << e.what() << std::endl;
  }
}

/*
B()
~B() // the entire vector vb is initialized with a copy
A() // default ctor
copy A // copy_count = 0
copy A
copy A // copy_count = 2, kaboom!
~A()
~A()
~A()
~B() // automatic
~B()
~B()
~B()
~B()
error: St9bad_alloc
*/

moral: When you aren't sure, test it.
And prove the solution.
Don't use pointers, you could use a boost::scoped_array.
 
K

kwikius

Hello everyone,

Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
    a = new int [N];
    b = new int [M];} catch (bad_alloc)

{
    // if a success, but b fail, should we try to delete[] a here to
avoid memory leak?

}


Interesting problem...

In theory in the above case you could do something like the following:


int * a = 0;
int * b = 0;
try {
a = new int [N];
try{
b = new int[M];
}
catch {bad_alloc){
delete a;
/* b didnt get allocated */
return;
}
/* delete a,b */
return;
}
catch bad_alloc{
/* neither a or b got allocated */
return;
}

However if looked at from a practical viewpoint, In case of
bad_alloc the most likely cause is that the system has run out of
memory.

Firstly It is a reasonable idea to try to detect bad_alloc
exceptions.

The problem then is once detected, what to do about them?

Its certainly useful ( IMO essential , at least polite) to try to
report this to the user, for which you need to catch the exception,
But bear in mind that you are equivalent to the drowning man in the
flooded room gulping the last bit of air, IOW you don't want to even
attempt any more heap allocations if at all possible, but pretty much
anything you do to output a diagnostic to the user may request
allocations. Neveretheless in this sitaution things can't get much
worse, so you should probably try doing the diagnostic (by calling
some code designed for this particular situation) and quit the
application if thats acceptable.

The point of this is...

If that's the strategy, you adopt then any dangling pointers will be
cleaned up by the system so its not worth worrying about them in
practise. Its also simple. You have done the right thing by the user.
Its their problem now.


If that strategy is unacceptable and you hope to continue the app,
then you are into a much more complicated ballgame. You have to find
some way to have some scratch space so you can then set about trying
the complicated task of regaining a useful amount of heap, and you
will need to deal with raw pointers owning heap real estate such as
'a'.

Another answer is. Dont use new, at least not in functions. If at all
possible allocate in class constructors and release in destructors.
(RAII) Then you will find that the problem is dealt with
automatically, because the destructor for the class allocated on the
stack is called automatically when an exception is thrown. This is how
most std::library types work under the hood (std::string , containers
etc

Smart pointers are another option rather than raw pointers.

regards
Andy Little
 
D

Daniel T.

George2 said:
Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
a = new int [N];
b = new int [M];
} catch (bad_alloc)
{
// if a success, but b fail, should we try to delete[] a here to
avoid memory leak?

}

The proper way to do the code above is:

a = 0;
b = 0;
try {
a = new int [N];
b = new int [N];
}
catch( bad_alloc ) {
delete [] a;
delete [] b;
}

But the best way is to turn 'a' and 'b' into vector<int>s.
 
Ad

Advertisements

J

James Kanze

Yes, but what about if you get a bad_alloc when allocating a? Then you
will try to delete whatever memory that the garbage in a points to. To
prevent this use something like this instead:
try {
int* a = 0;
a = new int[N];
int* b = new int[N];
}
catch (bad_alloc)
{
delete[] a;
}
Well, the idea is right but the implementation is wrong,
because a will be out of scope in the delete statement.
Moreover, unless a and b are deleted inside the try, the code
will leak memory if it succeeds, because once a and b are out
of scope, there's no further opportunity to delete the memory.
An alternative:
int* a = 0;
try {
a = new int[N];
int* b = new int[N];
// do additional work here
delete[] b;
delete[] a;
} catch (bad_alloc) {
delete[] a;
}
I agree with you that smart pointers are the way to go here :)

But not std::auto_ptr, since it does delete ptr, and not
delete[] ptr.

I actually disagree about using smart pointers here.
std::vector seems far more appropriate.
 
J

James Kanze

On Jan 5, 3:04 pm, George2 <[email protected]> wrote:
However if looked at from a practical viewpoint. In case of
bad_alloc the most likely cause is that the system has run out
of memory.

As a result of 1) your application using too much memory in
handling a specific request---in which case, you can return an
error (e.g. insufficient resources) for the request, and still
continue to operate, or 2) your application leaks memory---in
which case, you really do need to get out of there, as quickly
as possible, because the situation isn't going to get any better
anytime soon.
Firstly It is a reasonable idea to try to detect bad_alloc
exceptions.
The problem then is once detected, what to do about them?

In the first case, above, you respond with an error to the
request, saying that you can't handle it.

Whether such cases are plausible or not depends a lot on the
application. I've worked on servers in which "requests" had a
more or less open structure (e.g. represented an arbitrary
expression, usually in some variant of RPN)---LDAP comes to
mind. In such cases, you don't want to abort the server just
because some client goes overboard with his search criteria in
one particular request. (But I'll admit that the case is pretty
special, and probably doesn't apply to most applications. Also,
if you find yourself in such a case, you'll have to work out
something to avoid stack overflow as well.)
Its certainly useful (IMO essential, at least polite) to try
to report this to the user, for which you need to catch the
exception,

Interesting. I've always replaced the new_handler.

If you replace the new_handler, then operator new will
effectively become a nothrow (provided the constructor of the
object cannot throw for other reasons). This can be useful in
certain situations.

Of course, if you replace the new_handler, then such an error
won't cause the destructors on the stack to be called. Which
may be a problem as well. I tend to organize things so that it
won't be a problem, as much as possible, because there are other
cases where they won't be called either (e.g. if you core dump).
Such cases are all probably errors, but then, if you get a
bad_alloc because the program leaks memory, that's a programming
error as well.

(I'm not saying that the points you're raising aren't valid.
Only that there are a lot of things that have to be considered,
depending on the actual application.)
But bear in mind that you are equivalent to the drowning man
in the flooded room gulping the last bit of air, IOW you don't
want to even attempt any more heap allocations if at all
possible, but pretty much anything you do to output a
diagnostic to the user may request allocations.

Referring to my two situations in the first paragraph I wrote:
In case 1, the stack walk back due to the exception will free up
all of the memory the request allocated, so by the time you
catch the exception, there should be no real problem. In case
2: I've always pre-allocated any memory that might be needed to
output such critical error messages before starting operation,
just to be sure that it was there if the case occured.
Neveretheless in this sitaution things can't get much worse,
so you should probably try doing the diagnostic (by calling
some code designed for this particular situation) and quit the
application if thats acceptable.
The point of this is...
If that's the strategy, you adopt then any dangling pointers
will be cleaned up by the system so its not worth worrying
about them in practise. Its also simple. You have done the
right thing by the user. Its their problem now.

You have very tolerant users. If my server goes down, even if
the reason is due to bad_alloc, my users complain to me. (In a
number of cases, there have even been conventional penalties for
down time.)
If that strategy is unacceptable and you hope to continue the app,
then you are into a much more complicated ballgame. You have to find
some way to have some scratch space so you can then set about trying
the complicated task of regaining a useful amount of heap, and you
will need to deal with raw pointers owning heap real estate such as
'a'.

You have to know why you ran out of memory. If the only
possible reason for running out of memory is a memory leak in
your code (a frequent case in the context I work, where the
server, once written, runs on a dedicated machine with no other
applications on it), then of course, continuing is out of the
question. If the reason is that you've received a request that
required too many resources, the problem is handled
automatically by aborting the request.
Another answer is. Dont use new, at least not in functions. If
at all possible allocate in class constructors and release in
destructors. (RAII) Then you will find that the problem is
dealt with automatically, because the destructor for the class
allocated on the stack is called automatically when an
exception is thrown. This is how most std::library types work
under the hood (std::string , containers etc
Smart pointers are another option rather than raw pointers.

If it's only memory you're worried about, garbage collection is
the easiest solution. The same issues arise for other
resources, however, or even just issues of system coherence
(transactional integrity).
 
J

James Kanze

George2 said:
Should I delete memory pointed by pointer a if there is
bad_alloc when allocating memory in memory pointed by
pointer b? I am not sure whether there will be memory leak
if I do not delete a.
Code:
try {
a = new int [N];
b = new int [M];
} catch (bad_alloc)
{
// if a success, but b fail, should we try to delete[] a here to
avoid memory leak? 
}
The proper way to do the code above is:
a = 0;
b = 0;
try {
a = new int [N];
b = new int [N];}
catch( bad_alloc ) {
delete [] a;
delete [] b;
}
But the best way is to turn 'a' and 'b' into vector<int>s.

Since when is the "best way" not the "proper way"? Your
solution is "correct", of course, as would be using
boost::scoped_array. But as you say, the best way is to use
std::vector< int >. Anything else is less good.
 
K

kwikius

You have very tolerant users.  If my server goes down, even if
the reason is due to bad_alloc, my users complain to me.  (In a
number of cases, there have even been conventional penalties for
down time.)

Its an interesting problem, and the solution is very dependent on the
context, the platform, the type of application and so on, as you say.

Its also quite tricky to diagnose who is to blame. It could be other
applications on the system, it could be that the size of some
structure is dependent on parameters supplied by the user, or it could
(dare I say it) even be the fault of the application.

The bare minimum is to try to get some feedback to the user about the
problem (ideally too to provide a probable cause and even if possible
a suggested solution), after all if users are complaining then you
have users. Its when they arent complaining that you need to worry...
either your system is perfect, or you have no users ;-)

After satisfying that criteria, then I agree that doing anything more
useful is complicated. For example the user may have asked for you to
create a huge structure, but you may have a memory leak anyway. In
this case backing off and (recursively) telling the user that their
last request was too big will be very frustrating!

That is a case I have encountered as a user, and its a very good
argument for not allocating raw pointers :)

I guess you also need to weigh up how much time you spend on error
feedback, versus the time you spend on adding cool new features.

Of course the app may be a compiler. For example one of the goals of
CLANG is provide better diagnostics. Ultimately, trying to provide
useful error feedback does come to dominate everything in many
applications ( The timeline for a useful C++ frontend is a couple of
years)

http://clang.llvm.org/

regards
Andy Little
 
G

Grizlyk

Erik said:
Or use some kind of smart pointer, in which case
you do not need to try-block since the pointers
will free any memory if the exception is thrown.

  auto_ptr<int> a = new int[N];
  auto_ptr<int> b = new int[N];

I agree. It is better to use any kind (standard or self-maded) of
wrapper to control ownership of memory or other shared resources. C++
hard desined for technic known as RAII (read http://www.hackcraft.net/raii/
).
 
Ad

Advertisements

G

Grizlyk

kwikius said:
int * a = 0;
int * b = 0;
try {
    a = new int [N]; ...
      delete a;

Excellent :). As i know, for each program we get at least one (hard to
detect and with random runtime apperance) error due to improper delete/
delete[] usage.

For example, the stupid program ( http://grizlyk1.narod.ru/cpp_new/gcc/utils
) for adding source lines into gcc asm output has 3 levels of patching
of detected errors. Take a look at the last patch, file "to_do.txt":

1. possible memory leakage.

void Terr::do_copy(const char *const who)
{
if(who)try
{
const uint len=strlen(who);
if(!len)return;

char *const tmp=new char[len+1];
strcpy(tmp,who);
msg_copied=tmp;
}
catch(...){ msg_shared="no memory"; }
}

"strcpy(tmp,who)" can throw while "tmp" has no owner

patch:
char *const tmp=new char[len+1];
try{ strcpy(tmp,who); }catch(...){ delete[] tmp; throw; }
msg_copied=tmp;

2. Wrong delete for arrray

~Terr::Terr(){ delete msg_copied; }

patch:
~Terr::Terr(){ delete[] msg_copied; }

3. Wrong delete for arrray

Terr& operator= (const Terr& obj)
{
if( &obj != this )
{
msg_shared=obj.msg_shared;
delete msg_copied; msg_copied=0;
do_copy(obj.msg_copied);
}
return *this;
}

patch:
if(msg_copied){delete[] msg_copied; msg_copied=0;}

I agree, that the errors appeared due to my negligent work, this is
very bad habbit for programming, but there are many other people with
the same behaviour in the world. This is constant fact of nature :).

And in addition, any desing work, being continuous iterational
process, inspires a little the negligence in work ( :) I have found
the couse ).

So, the only way to prevent the errors is explicit memory
declarations:

char * ptr; //C-style pointer
auto char * ptr; //can not delete/delete[]
heap char * ptr; //can delete heap/delete
heap[] char * msg_copied; //can delete heap[]/delete[]
other_memory_type char *ptr; //can delete other_memory_type

Maybe it will be added to C++.

Maksim A. Polyanin
old page about some C++ improvements:
http://grizlyk1.narod.ru/cpp_new
 
P

Pete Becker

Erik said:
Or use some kind of smart pointer, in which case
you do not need to try-block since the pointers
will free any memory if the exception is thrown.

  auto_ptr<int> a = new int[N];
  auto_ptr<int> b = new int[N];

I agree. It is better to use any kind (standard or self-maded) of
wrapper to control ownership of memory or other shared resources.

Well, not "any kind". Just an appropriate kind, which, in this example,
auto_ptr is not. It uses scalar delete, not vector delete, so the
behavior when it stores a pointer to a new'ed array is undefined.
 
P

peter koch

kwikius said:
int * a = 0;
int * b = 0;
try {
    a = new int [N]; ...
      delete a;

Excellent :). As i know, for each program we get at least one (hard to
detect and with random runtime apperance) error due to improper delete/
delete[] usage.
Not in idiomatic C++ where you "never" use operator delete [].
For example, the stupid program (http://grizlyk1.narod.ru/cpp_new/gcc/utils
) for adding source lines into gcc asm output has 3 levels of patching
of detected errors. Take a look at the last patch, file "to_do.txt":

It is quite stupid from a C++ viewpoint as it looks more like C. In
this case, You should expect using C, not C++ style.
1. possible memory leakage.

    void  Terr::do_copy(const char *const who)
     {
      if(who)try
       {
        const uint len=strlen(who);
        if(!len)return;

        char *const tmp=new char[len+1];
        strcpy(tmp,who);
        msg_copied=tmp;
       }
      catch(...){ msg_shared="no memory"; }
     }

"strcpy(tmp,who)" can throw while "tmp" has no owner

This is not possible so far as I know. strcpy is C and thus does not
throw. Did you write your own strcpy?
patch:
        char *const tmp=new char[len+1];
        try{ strcpy(tmp,who); }catch(...){ delete[] tmp; throw; }
        msg_copied=tmp;

2. Wrong delete for arrray

    ~Terr::Terr(){ delete msg_copied; }

patch:
    ~Terr::Terr(){ delete[] msg_copied; }

3. Wrong delete for arrray

    Terr& operator= (const Terr& obj)
     {
      if( &obj != this )
       {
        msg_shared=obj.msg_shared;
        delete msg_copied; msg_copied=0;
        do_copy(obj.msg_copied);
       }
      return *this;
     }

patch:
        if(msg_copied){delete[] msg_copied; msg_copied=0;}

I agree, that the errors appeared due to my negligent work, this is
very bad habbit for programming, but there are many other people with
the same behaviour in the world. This is constant fact of nature :).

Well... you can't fight bad programming in any language.
And in addition, any desing work, being continuous iterational
process, inspires a little the negligence in work ( :) I have found
the couse ).

So, the only way to prevent the errors is explicit memory
declarations:

char * ptr;                  //C-style pointer
auto char * ptr;             //can not delete/delete[]
heap char * ptr;             //can delete heap/delete
heap[] char * msg_copied;    //can delete heap[]/delete[]
other_memory_type char *ptr; //can delete other_memory_type

Maybe it will be added to C++.
Why? We already have std::vector (and std::string). Using either of
these would have avoided your problems./Peter
 
A

Andre Kostur

Hello everyone,


Should I delete memory pointed by pointer a if there is bad_alloc when
allocating memory in memory pointed by pointer b? I am not sure
whether there will be memory leak if I do not delete a.

Code:
try {
a = new int [N];
b = new int [M];
} catch (bad_alloc)
{
// if a success, but b fail, should we try to delete[] a here to
avoid memory leak?

}

Yes, but what about if you get a bad_alloc when allocating a? Then you
will try to delete whatever memory that the garbage in a points to. To
prevent this use something like this instead:

try {
int* a = 0;
a = new int[N];
int* b = new int[N];
}
catch (bad_alloc)
{
delete[] a;
}

Bad advice: a isn't in scope in the catch clause.
Or use some kind of smart pointer, in which case you do not need to try-
block since the pointers will free any memory if the exception is thrown.

auto_ptr<int> a = new int[N];
auto_ptr<int> b = new int[N];

Worse advice. You may not store pointers returned by new[] into an
auto_ptr!
 
G

Grizlyk

peter said:
As i know, for each program we get at least one (hard to
detect and with random runtime apperance) error due
to improper delete/delete[] usage.

Not in idiomatic C++ where you "never" use operator delete [].

I see the Old lovely topic - a special meaning of std library in the
world :).

I suspect, you are speaking about ideal situation, where we do not use
C-style arrays or C-style arrays allocated in heap, because we are
replacing them with the help of appropreate wrappers, don't?

I think, we even can go further, and can refuse from explicit raw
memory management with new and delete, and replace all of them with
appropreate wrappers and its messages: wrapper(...), ~wrapper,
wrapper_new(...) etc.

Let's move discussion about the ideas to some lines below.
It is quite stupid from a C++ viewpoint as it looks
more like C. In this case, You should expect using C,
not C++ style.

"stupid from a C++ viewpoint"
Program can not be stupid due to viewpoint of concrete style or
paradigm. Stupid is just because simple, the program does nothing,
copying some lines from several files into one file.

"looks more like C"?
How will you express the following code from the program with the help
of C and why:

code example
// ***********************
template <class Tobj, class Tc_heap=Theap_array<Tobj> >
class Tarray_holder:
public Nholder::Tarray_holder_intf<Tobj,Tc_heap>
{
typedef Nholder::Tarray_holder_intf<Tobj,Tc_heap> Tparent;
using Tparent::memory;

public:
//from new Tobj[]
Tarray_holder&
set_array (Tobj *const obj)
{ Tparent::set_array(obj); return *this; }

Tarray_holder&
operator= (Tobj *const obj)
{ return set_array(obj); }

Tarray_holder(Tobj *const obj=0):Tparent(obj){}

~Tarray_holder(){ memory.destroy(); }

private:
Tarray_holder(const Tarray_holder&);
void operator= (const Tarray_holder&);
};

// *******************
//lists of reffered lines
list<Tfile> files;
uint files_size=0;

// *********************************************
// *********************************************
int main(int argc, char *argv[])
{
FILE *fo=0;

try{
if(argc!=2)usage();

char *in_fname=argv[1];
Tarray_holder<char> out_fname;

{
out_fname= new char[VALUE];
strcpy( out_fname(0), in_fname );

fo=fopen(out_fname(0),"wt");
if(!fo)throw Terr( out_fname(0) );
}

for(;;)
{
if(feof(fi))break;

//next line
getln(buf,MAX_LEN,fi);
++asm_lines;
if(!buf[0])continue;

//test file number is dublicated
if(
files_size
&& ( find_file(number) != files.end() )
)
{
f_st[0]='"';
f_end[0]='"';
fprintf(
stderr,
tpl_bad_format,
asm_lines,
file_sign,
"dublicated file number",
buf);
continue;
}

files.push_back(tmp);
++files_size;
}

// ******************
//try
}
catch(const char* err)
{ fprintf(stderr,"error: %s\n",err); }

catch(Terr& err)
{ fprintf(stderr,"error: %s\n",err.what()); }

catch(...)
{ fprintf(stderr,"error: %s\n","unknown"); }

// ******************
//main
}
end of code example
1. possible memory leakage.
        char *const tmp=new char[len+1];
        strcpy(tmp,who);
        msg_copied=tmp;
       }
      catch(...){ msg_shared="no memory"; }
"strcpy(tmp,who)" can throw while "tmp" has no owner

This is not possible so far as I know.
strcpy is C and thus does not throw.
Did you write your own strcpy?

I trust C-library in most cases, but for some situation wrappers or
even code replacement required for C-style function in C++ scope. In
the case of "strcpy", that will be comiled into "rep movsl", what kind
of replacement could be done without lost of perfomance?

Often std::strcpy can produce one of SIGxxx, so the best solution is
if target C++ executable enviroment will work to convert hardware
exception into C++ exception. The other solution is explicit throwing
exception from not_std::strcpy implementation.

Looking at the code, it is impossible to say what kind of strcpy
implementation are used, because the code is independent from any
strcpy implementation. I think the independence is reason of
appearence of any function and especially a library.

Original code is not safe, if exception will be thrown, and modified
code is safe. Both of them can not hold on if power of CPU will be
switched off or program will be terminated by OS during strcpy
execution.
Well... you can't fight bad programming in any language.

Are you think, that good programmer work only with assembler or even
directly with CPU opcodes? I guess you beleive no :). The goal of any
high-level language to reduce number of details, that must be used by
programmer simultaneously, to regroup the details into separated and
independent structures. The details with delete/delete[] look like
variable without type.
So, the only way to prevent the errors is explicit memory
declarations:
char * ptr;                  //C-style pointer
auto char * ptr;             //can not delete/delete[]
heap char * ptr;             //can delete heap/delete
heap[] char * msg_copied;    //can delete heap[]/delete[]
other_memory_type char *ptr; //can delete other_memory_type
Maybe it will be added to C++.

Why? We already have std::vector (and std::string). Using either of
these would have avoided your problems.

For example, just because C-arrays are not prohibited. But speaking
seriously, we sometimes need low-level dinamic buffers for simple DTA
and so on, with special behaviour, so we can write wrappers (other
than vector<>) and use raw memory management.

And returning to suspended idea about "idiomatic C++ where you never
use operator delete []".

I agree, this is not a best way to prove anything by linking to any
authority only, but some of the following ideas are quite
undestandable.

Somewhere about 90-99 years Stroustrup wrote that:

1. C++ was designed to do not insist on any concrete way of
programming. If you say, that the way is poor, you must say what
conrete thing is a problem with the way. The fact of existance of
other ways is not enough.

2. C++ was designed to be set of orthogonal, self-independed parts of
solid language, that means, that you can select and use any set of
parts you wish. If you say, that the part of language must be used
here, you must say what conrete thing is a problem without. The fact
of existance of other parts is not enough.

3. Library ( he was speaking about io implementation ) is _not_ a part
of C++ language. And it is right, because there are many libraries in
the world.

For OOP paradigm the fact of existance of any concrete interface is
often not a problem, due to free-standing classes and functions, that
can be used as adaptors (without any overhead).

It is possible, that under pressure of inconming improvements he has
changed his mind, but it is bad only for him :). Just because we begin
to insist on concrete way of programming or on using of concrete parts
of language.

I can understand people, who wants to remove all modifications into
library, in order to save C++ simple and alive, but it is not always
possible.

Maybe it would be better to strictly divide internals of C++,
implemented by std library, and real user-defined classes, implemented
by std library, that has no any relation to language itself, but only
to certain paradigms or ways of programming.

In the case noone will require to use any library or part of library,
including std library.

From the first view, the best solution to control modification - to
make simple (without syntax shugar and multy-ways of implementation of
anything) core language, including all important stuffs to implement
all supported paradigms. The core could be keeped unmodified, and
extentions or dialects of the core could be added/removed by standard
and then adjusted and used by user in free manner, but i agree, there
are many difficulties in the language like this.

4. I agree, that std library improve portability of code, but it is
impossible to write universal library. It is much better to include
stuffs into language to easy work with inteface of any concrete
library.

(If one want to use std library, take a list of library interfaces and
store the structure into own memory. There are examples, that can help
anybody to learn the library.)

The presence of std library make a strange thing - people became to
see C++ over stdlib: array is a vector<> etc. But it is not true,
Tarray_holder<> is array also.

I am shure, that some people do it from best feeling, but it is
impossible to write with C++ without understanding internals of C++:
memory layout, way of transfer of parameters, exception implementation
etc.

C++ is not like basic, you always will catch unexpected errors without
the knowledge or with the wrong or week knowledge.

It is the same as you can not use profesional OOP libraries without
base knowledge about OOP design, in fact, the libraries only help you
do not repeat the work is done.

In order to be independed from internals of C++ some people invent
artificial rules that is even more complex than original, but has no
any undestandable base. Real rules with example from any real
architecture is easy to understand, than artificial rules.

So large message :).

Maksim A. Polyanin
old page about some C++ improvements:
http://grizlyk1.narod.ru/cpp_new
 
Ad

Advertisements

K

kwikius

kwikius said:
int * a = 0;
int * b = 0;
try {
    a = new int [N]; ...
      delete a;

Excellent :). As i know, for each program we get at least one (hard to
detect and with random runtime apperance) error due to improper delete/
delete[] usage.

You got me!

I did spot it some time after I posted, and in a later post started
talking about memory leaks...

What can I say except I don't use raw pointers to heap if at possible.
The above is just one more ouch!.

regards
Andy Little
 
J

James Kanze

Its an interesting problem, and the solution is very dependent
on the context, the platform, the type of application and so
on, as you say.
Its also quite tricky to diagnose who is to blame.

By definition, I am to blame. (Or rather, my client, who is
providing the turn key system.)
It could be other applications on the system,

It's a dedicated system. There aren't (or shouldn't be) any
other "applications". Of course, there could be a bug in some
system service, that caused it to leak memory. But since we
decided to use Sun Solaris, running on a Sparc, rather than some
other system, that's our fault too. The contract is clear:
10.000 Euro per minute for down time. (I presume that there are
exceptions if, e.g. someone carelessly unplugs the machine, or
it gets destroyed in a terrorist attack, or something like
that.)
it could be that the size of some structure is dependent on
parameters supplied by the user,

We verify the parameters supplied by the user (the
configuration) before accepting it.
or it could (dare I say it) even be the fault of the
application.

As I said, the assumption is that if the application gets
bad_alloc, it is leaking memory.
The bare minimum is to try to get some feedback to the user
about the problem (ideally too to provide a probable cause and
even if possible a suggested solution),

We have logs, we can change the log configuration without
stopping the process, and we can even ftp into the users machine
to recover the log.
after all if users are complaining then you have users. Its
when they aren't complaining that you need to worry... either
your system is perfect, or you have no users ;-)

If your system is handling some critical job, it had better be
"perfect". (In fact, there are complaints, and there are
complaints. There's a very great difference between someone not
liking the background color on a monitor, and the system
crashing, and shutting down all long distance telephone services
in Germany.)
After satisfying that criteria, then I agree that doing
anything more useful is complicated. For example the user may
have asked for you to create a huge structure, but you may
have a memory leak anyway. In this case backing off and
(recursively) telling the user that their last request was too
big will be very frustrating!
That is a case I have encountered as a user, and its a very
good argument for not allocating raw pointers :)

Or using garbage collection. In practice, the most critical
systems I've worked on have used neither garbage collection nor
smart pointers. They have used exceptionally good software
development processes, however, with effective code review,
paying particular attention to memory management issues.
I guess you also need to weigh up how much time you spend on
error feedback, versus the time you spend on adding cool new
features.

A cool new feature which disrupts telephone service on a
national level won't go over very well. A cool new feature
which means that the breaks won't apply in the locomotive won't
go over too well. A cool new feature which results in several
cellular phones being allocated the same IP address won't go
over too well.

On most of the systems I work on, the "user" never actually sees
the system, or knows what features it has. When someone in
Frankfurt calls someone in Berlin, he's (hopefully) totally
unaware that his call passes through machines that I've
programmed.
Of course the app may be a compiler. For example one of the
goals of CLANG is provide better diagnostics. Ultimately,
trying to provide useful error feedback does come to dominate
everything in many applications ( The timeline for a useful
C++ frontend is a couple of years)

For a lot of programs, error handling is most of the code. But
that can mean many different things---and hopefully, it
generally means user error handling, and not handling internal
errors in the code. (Even in the telephone applications, most
of the code was necessary to handle rerouting in case of
hardware problems. Error handling.)
 
P

peter koch

peter said:
As i know, for each program we get at least one (hard to
detect and with random runtime apperance) error due
to improper delete/delete[] usage.
Not in idiomatic C++ where you "never" use operator delete [].

I see the Old lovely topic - a special meaning of std library in the
world :).

Not at all. You did not use the standard library which was what I
hinted you should do.
I suspect, you are speaking about ideal situation, where we do not use
C-style arrays or C-style arrays allocated in heap, because we are
replacing them with the help of appropreate wrappers, don't?

You use the standard elements available, e.g. std::string. This is
very good advice.
I think, we even can go further, and can refuse from explicit raw
memory management with new and delete, and replace all of them with
appropreate wrappers and its messages: wrapper(...), ~wrapper,
wrapper_new(...) etc.

That probably depends on your application, and often I believe you
can. But this was not what we were talking about above.
Let's move discussion about the ideas to some lines below.



"stupid from a C++ viewpoint"
Program can not be stupid due to viewpoint of concrete style or
paradigm. Stupid is just because simple, the program does nothing,
copying some lines from several files into one file.

No. The program is "stupid" because it does not use what is available
but insists on using elements of a coding style that were meant for
more low-level programming.
"looks more like C"?
How will you express the following code from the program with the help
of C and why:

code example [snip]
end of code example

I am not going to spend my time determining what your code is supposed
to do, but a glimpse shows that your code is basically C, with strcpy,
fprintf and FILE*. The template is an attempt to have a "smart"
pointer to some storage perhaps? I am afraid I fail to see the purpose
of that class.
1. possible memory leakage.
        char *const tmp=new char[len+1];
        strcpy(tmp,who);
        msg_copied=tmp;
       }
      catch(...){ msg_shared="no memory"; }
"strcpy(tmp,who)" can throw while "tmp" has no owner
This is not possible so far as I know.
strcpy is C and thus does not throw.
Did you write your own strcpy?

I trust C-library in most cases, but for some situation wrappers or
even code replacement required for C-style function in C++ scope. In
the case of "strcpy", that will be comiled into "rep movsl", what kind
of replacement could be done without lost of perfomance?

Did you measure your perceived loss?
Often std::strcpy can produce one of SIGxxx, so the best solution is
if target C++ executable enviroment will work to convert hardware
exception into C++ exception. The other solution is explicit throwing
exception from not_std::strcpy implementation.

A SIG is not a C++ exception. Do not transform hardware exceptions
into C++ exceptions.
Looking at the code, it is impossible to say what kind of strcpy
implementation are used, because the code is independent from any
strcpy implementation. I think the independence is reason of
appearence of any function and especially a library.

Original code is not safe, if exception will be thrown, and modified
code is safe. Both of them can not hold on if power of CPU will be
switched off or program will be terminated by OS during strcpy
execution.
Well... you can't fight bad programming in any language.

Are you think, that good programmer work only with assembler or even
directly with CPU opcodes? I guess you beleive no :). The goal of any
high-level language to reduce number of details, that must be used by
programmer simultaneously, to regroup the details into separated and
independent structures. The details with delete/delete[] look like
variable without type.

The point is that new[] is a "low-level" detail, practically never
needed in a C++ program.
So, the only way to prevent the errors is explicit memory
declarations:
char * ptr;                  //C-style pointer
auto char * ptr;             //can not delete/delete[]
heap char * ptr;             //can delete heap/delete
heap[] char * msg_copied;    //can delete heap[]/delete[]
other_memory_type char *ptr; //can delete other_memory_type
Maybe it will be added to C++.
Why? We already have std::vector (and std::string). Using either of
these would have avoided your problems.

For example, just because C-arrays are not prohibited. But speaking
seriously, we sometimes need low-level dinamic buffers for simple DTA
and so on, with special behaviour, so we can write wrappers (other
than vector<>) and use raw memory management.

I do not know what DTA is but if you can use operator new you can also
use std::vector. And if you can't use std::vector, I can't see how you
can use operator new[].
And returning to suspended idea about "idiomatic C++ where you never
use operator delete []".

I agree, this is not a best way to prove anything by linking to any
authority only, but some of the following ideas are quite
undestandable.

Somewhere about 90-99 years Stroustrup wrote that:

1. C++ was designed to do not insist on any concrete way of
programming. If you say, that the way is poor, you must say what
conrete thing is a problem with the way. The fact of existance of
other ways is not enough.

You did show that yourself, I believe having three errors in a 20
lines of code because you refused to use the standard library and
insisted on using lower level tools that you did not understand.
2. C++ was designed to be set of orthogonal, self-independed parts of
solid language, that means, that you can select and use any set of
parts you wish. If you say, that the part of language must be used
here, you must say what conrete thing is a problem without. The fact
of existance of other parts is not enough.

You can express multiplication by using addition and a for loop, but
doing so would be silly.
3. Library ( he was speaking about io implementation ) is _not_ a part
of C++ language. And it is right, because there are many libraries in
the world.

I am not sure I understand you here, but the C++ standard library is
very much a part of the C++ language.

I've snipped the rest of your post as I am afraid I do not quite
understand what you are trying to tell (apart that the std::library is
not part of C++ which is wrong).

/Peter
 
Ad

Advertisements

G

Grizlyk

peter said:
Not at all. You did not use the standard library which was what I
hinted you should do.

I like it, let's go :).

I think the problem of standarding any high-level class, as vector<>
does, is the nature of the "high-levelness".

In comparison with POD types, there are no problems for POD types to
detect and implement the behaviour of the POD types clear and not-
disputable, only due to "trivialness" of nature of POD types.

But the non-trivial behaviuor of the not-POD, high-level classes
results to the conclusion, that it is impossible (as real existed
classes prove), to make any certain universal high-level class, that
can be high-efficiently implemented and used for all possible cases.

*It is because, for the high-level classes, _the conditions_ of best
definition of the classes's interfaces and implementations of each
concrete case _contradict each other_, unlike the same _the
conditions_ for trivial (POD) types.

The contradictions results in, that there are more than one
implementation for logically-single concrete high-level class, and
each the concrete implementation differs from other implementations by
concrete requirements, that has been selected for the concrete
implementation befor their development.

There are more than single interface to implement similar logical
targets by similar but different high-level classes.

For example, class vector<> as implementation of arrays.

The standard vector<> has been developed to be part of solid library,
to work with algorithms of the library etc, and they are primary
conditions, that have been selected befor development of the class
vector<>.

The concrete form of vector<>'s interface and implementation are
defined for the first part by the primary conditions of development -
to work completele with the library, and no any other development
reasons could change or even make influence on the primary conditions.

There are some things, that we can not guarantee, that in certain
concrete situation, the standard vector<> will have the best
performans and be efficient.

The things is not a bad implementation of a good idea, there is other
cause of the throubles.

Instead of standard vector<>, only special new alt_vector<> can
guarantee the best performans and be efficient, if the alt_vector<>
has been developed for the concrete situation and the alt_vector<> has
maximal suitable interface and maximal efficient implementation.

Why standard vector<> can not? There are some causes:

When we are using standard vector<>, we reffer only to interface of
the vector<>, more, we do it with intention, to breake link between
our code and implementation of vector<>. The primary goal of creation
of class vector<> is hiding the implementation of class vector<> from
us, to be independent from the implementation of class vector<>.

But standard can not guarantee, that performans and efficientness of
the hidden (and not covered by standard) implementation of vector<> in
the certain concrete case will be even nor worse, than for specific
for the case alt_vector<>, just because standard of vector<> is
standard of interface of vector<> and know nothing of the concrete
implementation of vector<>.

So, the necessity of the required standard implementation of vector<>
contradicts with the idea to make vector<> as class. The vector<> (as
any ordinary class or function) creates with the purpose _to does not
make standard implementation of the concrete vector<>_ and to hide the
implementation by interface of vector<> instead. What is the reason to
make standard interface of vector<>, if we later will reffer to
concrete standard implementation of the vector<> only?

The class alt_vector<> could be created exactly to be independent from
unknown implementation of standard vector<>, more, the presence of the
class alt_vector<> only real guarantee the best of all, that can not
guarantee standard in the concrete situation.

The presence of the class alt_vector<> guarantee, that the
implementation of the class alt_vector<> will be best of all for the
concrete case.

The second question about suitable for the concrete case interface of
standard vector<> is more easy, because new alt_vector<> can use OOP
design pattern facade, adapter, bridge etc to use existing
implementation of vector<> without overhead (it is responsibility of
implementor of "alt_vector<> via vector<>" to be ensure, that vector<>
has suitable implementation for the case).

*It is impossible to guarantee the best implementation of high-level
classes for all possible cases only with the help of standard univeral
interfaces of the high-level classes, creating the interfaces with
intention (as for any other ordinary interfaces) to hide the best
implementation by the interfaces, to leave the best implementation
outside of scope of standard.

I hope, no one will insist that there is best implementation of
anything and will add the implementation to sandard.

Conclusion:

For the first time look, to support the complex, not-trivial high-
level classes standard must contain:
1. low-level, raw stuffs as _part of language_, suitable for reliable
creation of the high-level classes by user;
2. some concrete professional implementations of the universal high-
level classes, intended to be _parts of ordynary libraries_ rather
than part of language itself.

What the reason to make POD type super_int as part of language, that
can not be used in all cases? As no reasons as for universal high-
level classes.

It is impossible to make standard concrete universal high-level
classes, and to say "we no need other high-level classes and no need
raw stuffs (as delete[]) of language to implement other high-level
classes by user".

I believe, the same is related to other things, for example, for C++
support of threads.

Selecting raw stuffs of language or universal high-level classes one
can make a vague conclusion (for example, variable visible outside of
"for" scope {for(int i=0;;++i){} if(!i)break;} is it good or bad?)

In order to control the stuffs by user and by standard, C++ needs
dialects(extentions) to be supported, as a way to make improvements
(properties of languages) more structured.

And at last, the alt_vector<> against vector<> can look for anybody
like an attempt to replace universal "printf" with low perfomace by
high-perfomanced series of "puts". But it is not the same, it is
really different things :)

We are speaking rather about replacement of universal "printf" by high-
perfomanced "printf" - they both do the same, and printf target is not
the same as target of the core part of language as array does.

Maksim A. Polyanin
old page about some C++ improvements:
http://grizlyk1.narod.ru/cpp_new
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top