pass char * as reference and reallocate memory for a pointer

H

happyvalley

Hi,
basically, the test function get a char pointer, and assigned a string
to it. then the string is passed back by the call-by-reference
mechanism. in test(), I reallocate some memory for the pointer, the
size is not fixed.

I remember, all new statement should be followed by a delete statement,

is there some memory leak here?


void test(char* &str)
{
// don't know how long the string might be
char *astring = "a string to return after thinking, not
fixed length";
str = new char[strlen(astring)+1];

strcpy(str, astring );
cout<<"test "<<str<<endl;

}


void main(void)
{
char *astr = "";

test(astr);
cout<<astr<<endl;
}
 
S

Salt_Peter

happyvalley said:
Hi,
basically, the test function get a char pointer, and assigned a string
to it. then the string is passed back by the call-by-reference
mechanism. in test(), I reallocate some memory for the pointer, the
size is not fixed.

I remember, all new statement should be followed by a delete statement,

is there some memory leak here?


void test(char* &str)
{
// don't know how long the string might be
char *astring = "a string to return after thinking, not
fixed length";
str = new char[strlen(astring)+1];

strcpy(str, astring );
cout<<"test "<<str<<endl;

}


void main(void)
{
char *astr = "";

test(astr);
cout<<astr<<endl;
}

Yes, thats a leak. Whats wrong with the string class? It has a member
function c_str() which returns a const ptr to char.

#include <iostream>
#include <ostream>
#include <string>

void test(std::string& r_s)
{
r_s += "a string to return after thinking";
}

int main()
{
std::string s;
test(s);
std::cout << s << std::endl;
}

/*
a string to return after thinking
*/
 
H

happyvalley

Salt_Peter said:
happyvalley said:
Hi,
basically, the test function get a char pointer, and assigned a string
to it. then the string is passed back by the call-by-reference
mechanism. in test(), I reallocate some memory for the pointer, the
size is not fixed.

I remember, all new statement should be followed by a delete statement,

is there some memory leak here?


void test(char* &str)
{
// don't know how long the string might be
char *astring = "a string to return after thinking, not
fixed length";
str = new char[strlen(astring)+1];

strcpy(str, astring );
cout<<"test "<<str<<endl;

}


void main(void)
{
char *astr = "";

test(astr);
cout<<astr<<endl;
}

Yes, thats a leak. Whats wrong with the string class? It has a member
function c_str() which returns a const ptr to char.

#include <iostream>
#include <ostream>
#include <string>

void test(std::string& r_s)
{
r_s += "a string to return after thinking";
}

int main()
{
std::string s;
test(s);
std::cout << s << std::endl;
}

/*
a string to return after thinking
*/

thanks for your reply, yes string works, just want to make it straight.
the main() passes a pointer to the test(), while the new statement
only allocate some memory for the pointer, not create a new pointer,
right. after return to the main(), the pointer will die when go out of
scope. right?
I put delete astr at the end of main(), no error.
how can I check if there is a memory leak?
thanks again
 
S

sam_cit

void main(void)
{
char *astr = "";

test(astr);
cout<<astr<<endl;
}

I see that when the function test is called the pointer is passed by
value, you are just passing the address that the pointer is pointing to
and any change of the pointer in the function will not reflect outside
and hence it is a memory leak...

Hope it helps...
 
H

happyvalley

I see that when the function test is called the pointer is passed by
value, you are just passing the address that the pointer is pointing to
and any change of the pointer in the function will not reflect outside
and hence it is a memory leak...

Hope it helps...

you mean, test(char * &str) is call by value, if so, how to pass the
char pointer by reference? thanks, get confused.

void test(char* &str)
{
char *astring = "a string to return after thinking";
str = new char[strlen(astring)+1];
strcpy(str, astring );
}
 
S

sam_cit

you mean, test(char * &str) is call by value, if so, how to pass the
char pointer by reference? thanks, get confused.

void test(char* &str)
{
char *astring = "a string to return after thinking";
str = new char[strlen(astring)+1];
strcpy(str, astring );
}

Pass the pointer by reference, pass the address of the pointer

test(&p_str)

void(char** p_p_str)
{
}

Hope it helps...
 
N

Noah Roberts

I see that when the function test is called the pointer is passed by
value, you are just passing the address that the pointer is pointing to
and any change of the pointer in the function will not reflect outside
and hence it is a memory leak...

No, it's passed by reference; see the definition of the test()
function.
From what I can see the "leak" is caused by the fact that there is no
"delete astr" at the end of main. It isn't technically a leak though
because a leak is a reoccuring allocation of memory that isn't deleted.
This one can't reoccur.

There's plenty of potential for problems in the OP's code though. It
is _extreemly_ tough to make safe char* functions. You will always
have to rely on developer vigilance to keep bugs out of the code when
dealing with char*. Such functions are very fragile in the face of
change. In comparison to std::string it just plain isn't worth the
trouble.
 
S

Salt_Peter

happyvalley said:
Salt_Peter said:
happyvalley said:
Hi,
basically, the test function get a char pointer, and assigned a string
to it. then the string is passed back by the call-by-reference
mechanism. in test(), I reallocate some memory for the pointer, the
size is not fixed.

I remember, all new statement should be followed by a delete statement,

is there some memory leak here?


void test(char* &str)
{
// don't know how long the string might be
char *astring = "a string to return after thinking, not
fixed length";
str = new char[strlen(astring)+1];

strcpy(str, astring );
cout<<"test "<<str<<endl;

}


void main(void)
{
char *astr = "";

test(astr);
cout<<astr<<endl;
}

Yes, thats a leak. Whats wrong with the string class? It has a member
function c_str() which returns a const ptr to char.

#include <iostream>
#include <ostream>
#include <string>

void test(std::string& r_s)
{
r_s += "a string to return after thinking";
}

int main()
{
std::string s;
test(s);
std::cout << s << std::endl;
}

/*
a string to return after thinking
*/

thanks for your reply, yes string works, just want to make it straight.
the main() passes a pointer to the test(), while the new statement
only allocate some memory for the pointer, not create a new pointer,
right. after return to the main(), the pointer will die when go out of
scope. right?
I put delete astr at the end of main(), no error.
how can I check if there is a memory leak?
thanks again

No, std::string s is an object with its own lifetime. It is passed by
reference to test(...). The program exhibits no leaks whatsoever. A
reference is akin to a const_pointer on steroids that can't be
reseated. You could do the same with a const pointer:

void test(std::string* const p_s)
{
*p_s += "a string to return after thinking";
// p_s = new std::string("another string"); // error, not allowed
}

Like a const pointer, a reference is not allowed to refer to another
object.
Thats safety built in to the design, the const keyword is critical. If
you take the discussion one step further: a const reference is
non-mutable _and_ not reseatable. So if wanted a function to display
the std::string and guarentee that the std::string cannot be modified
by anybody:

void display(const std::string& r_s) // by const ref
{
std::cout << r_s << std::endl;
}

display(...) is not allowed to change that string. It can only read it.
Its equivalent in pointer-speak:

void display(const std::string* const p_s) // by const ptr to const s
{
std::cout << *p_s << std::endl;
}

I'ld suggest writing code without new/delete. You'll find that such
code is much easier to write and maintain.
 
V

Vyacheslav Kononenko

Salt_Peter said:
I'ld suggest writing code without new/delete. You'll find that such
code is much easier to write and maintain.

Hmm very strange recommendation. I would hardly imagine any nontrivial
C++ application, that does not use objects from the heap.
 
N

Noah Roberts

Vyacheslav said:
Hmm very strange recommendation. I would hardly imagine any nontrivial
C++ application, that does not use objects from the heap.

True, but it can still be avoided. For example in this case. If you
use std::string there is no need to use new/delete yourself. Rely on
the standard library and language mechanics to do it for you.
 
V

Vyacheslav Kononenko

Noah said:
True, but it can still be avoided. For example in this case. If you
use std::string there is no need to use new/delete yourself. Rely on
the standard library and language mechanics to do it for you.

Yes it can and usually it should. But I have an impression that this
case is just a simplified test of concept on how a function can return
a dynamically allocated object. So that recommendation could be
understood as generic by the author.
 
G

Gavin Deane

Pass the pointer by reference

That's exactly what the OP did.

void test(char* &p_str);

is not passing by value.
pass the address of the pointer

Not necessary.
test(&p_str)

void(char** p_p_str)
{
}

That's worse than what the OP had. If someone is having difficulty with
pointers and memory management, adding an extra level of indirection
won't help understanding. Moreover, the OP's passing by reference was
equivalent to passing a const pointer to a char*. You've thrown away
that const.

Gavin Deane
 
S

Salt_Peter

Vyacheslav said:
Hmm very strange recommendation. I would hardly imagine any nontrivial
C++ application, that does not use objects from the heap.

Who said not to use the heap? Since when do you require new/delete for
the heap? Entire applications can be written, and are written, without
a single delete - and those applications are rock solid.
Whats stopping you from using a smart_pointer like std::auto_ptr,
boost::shared_ptr or boost::shared_array, etc? Why not let a std
container provide RAII for you? Even in the case where you must
allocate elements, why deal with the headaches of deallocation when you
can do as follows:

#include <deque>
#include <boost/shared_ptr.hpp>

class A { ];
int main()
{
typedef boost::shared_ptr< A > SPtr_A;
std::deque< SPtr_A > v;
v.push_back( SPtr_A(new A) );
}

In the above, the responsability of the heap allocation is transferred
to the vector.
The ultimate reason, in the end, for such a recommendation, astonishly
enough, is that it is easier and safer to program without new/delete.
Consider:

#include <boost/shared_ptr.hpp>

struct Base { };
struct Derived : public Base { };

int main()
{
// Base* p_base = new Derived;
// delete p_base; // memory leak, ~Base() is not virtual
boost::shared_ptr< Base > sp(new Derived);
}

If you did the above with new/delete, you'ld get a leak because the
Base class doesn't have a virtual destructor. Yet that is not an issue
with boost::shared_ptr, which correctly invokes both c~tors
polymorphicly for you.
 
N

Noah Roberts

Salt_Peter said:
Vyacheslav said:
Hmm very strange recommendation. I would hardly imagine any nontrivial
C++ application, that does not use objects from the heap.

Who said not to use the heap? Since when do you require new/delete for
the heap? Entire applications can be written, and are written, without
a single delete - and those applications are rock solid.
Whats stopping you from using a smart_pointer like std::auto_ptr,
boost::shared_ptr or boost::shared_array, etc? Why not let a std
container provide RAII for you? Even in the case where you must
allocate elements, why deal with the headaches of deallocation when you
can do as follows:

#include <deque>
#include <boost/shared_ptr.hpp>

class A { ];
int main()
{
typedef boost::shared_ptr< A > SPtr_A;
std::deque< SPtr_A > v;
v.push_back( SPtr_A(new A) );
}

In the above, the responsability of the heap allocation is transferred
to the vector.

No more so than it was before. You still called 'new' thus you still
performed the heap allocation of your new A. This heap memory has been
handed off to an RAII object for deallocation but you still allocated
it and the vector isn't the one responsible...to make that clear make a
copy of your smart pointer and see if it's still pointing at a valid
object after the vector is destroyed.
The ultimate reason, in the end, for such a recommendation, astonishly
enough, is that it is easier and safer to program without new/delete.
Consider:

#include <boost/shared_ptr.hpp>

struct Base { };
struct Derived : public Base { };

int main()
{
// Base* p_base = new Derived;
// delete p_base; // memory leak, ~Base() is not virtual
boost::shared_ptr< Base > sp(new Derived);
}

If you did the above with new/delete, you'ld get a leak because the
Base class doesn't have a virtual destructor. Yet that is not an issue
with boost::shared_ptr, which correctly invokes both c~tors
polymorphicly for you.

smart pointers cannot take care of all situations when this is a
problem. Also, boost::shared_ptr is the only one that will correctly
deal with the object when finished, but I believe this is only true if
the pointer passed into it was a Derived* (the "polymorphism" in this
case is static). In other words, a non-virtual destructor in a
polymorphic base class is a problem no matter what.

int main()
{
Base * b = new Derived;
boost::shared_ptr<Base> sb = boost::shared_ptr<Base>(b); //
} // Base's destructor called.
 
V

Vyacheslav Kononenko

Salt_Peter said:
Who said not to use the heap? Since when do you require new/delete for
the heap? Entire applications can be written, and are written, without
a single delete - and those applications are rock solid.

I totally agree with this statement. Yes they can be written. But it
does not mean that all of them must be or should be written this way.
Also it does not mean that every application will benefit of this.
Otherway we can forget about C++ and migrate to java.
Whats stopping you from using a smart_pointer like std::auto_ptr,
boost::shared_ptr or boost::shared_array, etc? Why not let a std
container provide RAII for you?

Nothing stops me. And I am using it. I am also aware that smart
pointers are not a silver bullet and there are situations when they do
not work well. But anyway pointers and memory management is base for
C++ and to recommend a beginner to avoid learn it is strange. There is
comp.lang.java for that.
 
S

Salt_Peter

Noah said:
Salt_Peter said:
Vyacheslav said:
Salt_Peter wrote:
I'ld suggest writing code without new/delete. You'll find that such
code is much easier to write and maintain.

Hmm very strange recommendation. I would hardly imagine any nontrivial
C++ application, that does not use objects from the heap.

Who said not to use the heap? Since when do you require new/delete for
the heap? Entire applications can be written, and are written, without
a single delete - and those applications are rock solid.
Whats stopping you from using a smart_pointer like std::auto_ptr,
boost::shared_ptr or boost::shared_array, etc? Why not let a std
container provide RAII for you? Even in the case where you must
allocate elements, why deal with the headaches of deallocation when you
can do as follows:

#include <deque>
#include <boost/shared_ptr.hpp>

class A { ];
int main()
{
typedef boost::shared_ptr< A > SPtr_A;
std::deque< SPtr_A > v;
v.push_back( SPtr_A(new A) );
}

In the above, the responsability of the heap allocation is transferred
to the vector.

No more so than it was before. You still called 'new' thus you still
performed the heap allocation of your new A. This heap memory has been
handed off to an RAII object for deallocation but you still allocated
it and the vector isn't the one responsible...to make that clear make a
copy of your smart pointer and see if it's still pointing at a valid
object after the vector is destroyed.

Yes, thats right, it is a heap allocation. The difference is that if
something occurs, like an exception thrown, your deletes won't get
skipped. If something exceptional throws the context, the vector gets
zapped, which invokes the shared_ptr's destructors for each element.
Thats clearly remitting the responsability of deallocation to that
vector (in the same way that relying on the stack for those elements is
RAII) . Obviously, if you make a copy of a shared_ptr, it won't be
destroyed (reference count).
smart pointers cannot take care of all situations when this is a
problem. Also, boost::shared_ptr is the only one that will correctly
deal with the object when finished, but I believe this is only true if
the pointer passed into it was a Derived* (the "polymorphism" in this
case is static). In other words, a non-virtual destructor in a
polymorphic base class is a problem no matter what.

int main()
{
Base * b = new Derived;
boost::shared_ptr<Base> sb = boost::shared_ptr<Base>(b); //
} // Base's destructor called.

no, sir. The above does the following:

~Derived()
~Base()

And it does so even if no virtual functions exist. To see how boost
does that: see boost's checked_delete.hpp.
 
S

Salt_Peter

Vyacheslav said:
I totally agree with this statement. Yes they can be written. But it
does not mean that all of them must be or should be written this way.
Also it does not mean that every application will benefit of this.
Otherway we can forget about C++ and migrate to java.

I'm not suggesting that a GC is needed, its not and smart_ptrs are a
better system. There is a growing inclination in the C++ community to
discourage heap allocations that don't use smart pointers with the
exception of self-recovering classes (thats how STL containers are
designed). They keep the programmer conscious and disciplined about
those allocations and simplifies the code.
Too many newbies think its ok to new overhere, cross fingers, and
delete overthere without understanding that allocations and
deallocations are not meant to be distributed (or ignored).
 

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

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,241
Members
46,831
Latest member
RusselWill

Latest Threads

Top