Wrong way to pass pointer by value in functions

D

DamonChong

Hi,

I am still struggling to master C++ and is trying to understand how to
achieve passing arguments using pointers. I got some questions that I
like to post to the experts here, hope you can help to clarify my
doubts. I'm using g++ version 3.3.4. I created 3 classes as below for
testing some concepts. The questions are written as comments in
Bclass.h file. Thank you for your time and tips!

------------runtime errors------------
{8=> main
Aclass created.
Bclass instantiated.
main: Aclass.h:19: void Aclass::test(): Assertion `b' failed.
Aborted


-------------file: main.cc------------
#include "Aclass.h"

int main(){
Aclass a;
a.test();
}

-------------file: Aclass.h-----------
#ifndef ACLASS_H
#define ACLASS_H

#include "Bclass.h"
#include <stack>
#include <cassert>

class Aclass{
public:
Aclass(){
std::cout << "Aclass created." << std::endl;
}
~Aclass(){ std::cout << "Aclass destructed." << std::endl; }

void test(){
Bclass *b=NULL;
if( box.empty() ){
create(b);
assert(b); // As expected this fails during runtime
/* Qn: Is the failure because pointer 'b' is pointing to NULL?
* Qn: Is the reason why the call to "create" function without effect
* because the local pointer 'ptr' was changed to point to a temporary
object?
*/
}
delete b;
}

protected:
void create(Bclass *ptr){
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine
/* Qn: Is the reason the assertion pass because local pointer 'b' is
* still referencing the memory?
* Qn: Is the memory release or considered unreferenced only if
* we get out of the "create" function?
*/
}

private:
std::stack<Bclass* > box;
};

#endif

-------------file: Bclass.h-----------
#ifndef BCLASS_H
#define BCLASS_H
#include <iostream>

class Bclass{
public:
Bclass(){ std::cout << "Bclass instantiated." << std::endl; }
~Bclass(){ std::cout << "Bclass destroyed." << std::endl; }
};
#endif
 
H

Howard

DamonChong said:
Hi,

I am still struggling to master C++ and is trying to understand how to
achieve passing arguments using pointers. I got some questions that I
like to post to the experts here, hope you can help to clarify my
doubts. I'm using g++ version 3.3.4. I created 3 classes as below for
testing some concepts. The questions are written as comments in
Bclass.h file. Thank you for your time and tips!

------------runtime errors------------
{8=> main
Aclass created.
Bclass instantiated.
main: Aclass.h:19: void Aclass::test(): Assertion `b' failed.
Aborted


-------------file: main.cc------------
#include "Aclass.h"

int main(){
Aclass a;
a.test();
}

-------------file: Aclass.h-----------
#ifndef ACLASS_H
#define ACLASS_H

#include "Bclass.h"
#include <stack>
#include <cassert>

class Aclass{
public:
Aclass(){
std::cout << "Aclass created." << std::endl;
}
~Aclass(){ std::cout << "Aclass destructed." << std::endl; }

void test(){
Bclass *b=NULL;
if( box.empty() ){
create(b);
assert(b); // As expected this fails during runtime
/* Qn: Is the failure because pointer 'b' is pointing to NULL?
Yes.

* Qn: Is the reason why the call to "create" function without effect
* because the local pointer 'ptr' was changed to point to a temporary
object?
Yes.

*/
}
delete b;
}

protected:
void create(Bclass *ptr){
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine
/* Qn: Is the reason the assertion pass because local pointer 'b' is
* still referencing the memory?

It passes because ptr is pointing to valid memory. There is no b here.
* Qn: Is the memory release or considered unreferenced only if
* we get out of the "create" function?

It's a memory leak, because you created it with new, but never delete it.

If you want to modify something, you need to pass it by reference or via a
pointer. This includes modifying pointers themselves. So you need to pass
the pointer by reference (or via a pointer-to-pointer). Try:

void create(Bclass* &ptr) {...

-Howard
 
H

Howard

Howard said:

Actually, that wasn't a correct response on my part. The pointer ptr is a
local copy (of the pointer b) in the create function. That copy was
assigned a value. But b itself was left unchanged, so it remained NULL.

-Howard
 
A

Axter

DamonChong said:
Hi,

I am still struggling to master C++ and is trying to understand how to
achieve passing arguments using pointers. I got some questions that I
like to post to the experts here, hope you can help to clarify my
doubts. I'm using g++ version 3.3.4. I created 3 classes as below for
testing some concepts. The questions are written as comments in
Bclass.h file. Thank you for your time and tips!

------------runtime errors------------
{8=> main
Aclass created.
Bclass instantiated.
main: Aclass.h:19: void Aclass::test(): Assertion `b' failed.
Aborted


-------------file: main.cc------------
#include "Aclass.h"

int main(){
Aclass a;
a.test();
}

-------------file: Aclass.h-----------
#ifndef ACLASS_H
#define ACLASS_H

#include "Bclass.h"
#include <stack>
#include <cassert>

class Aclass{
public:
Aclass(){
std::cout << "Aclass created." << std::endl;
}
~Aclass(){ std::cout << "Aclass destructed." << std::endl; }

void test(){
Bclass *b=NULL;
if( box.empty() ){
create(b);
assert(b); // As expected this fails during runtime
/* Qn: Is the failure because pointer 'b' is pointing to NULL?
* Qn: Is the reason why the call to "create" function without effect
* because the local pointer 'ptr' was changed to point to a temporary
object?
*/
}
delete b;
}

protected:
void create(Bclass *ptr){
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine
/* Qn: Is the reason the assertion pass because local pointer 'b' is
* still referencing the memory?
* Qn: Is the memory release or considered unreferenced only if
* we get out of the "create" function?
*/
}

private:
std::stack<Bclass* > box;
};

#endif

-------------file: Bclass.h-----------
#ifndef BCLASS_H
#define BCLASS_H
#include <iostream>

class Bclass{
public:
Bclass(){ std::cout << "Bclass instantiated." << std::endl; }
~Bclass(){ std::cout << "Bclass destroyed." << std::endl; }
};
#endif


That problem is that yuo're passing the pointer by value.
If you want to modify the calling functions argument, you have to
either pass the pointer by reference, or pass a pointer to a pointer.
Example:
//Ref
void create(Bclass *& ptr){
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine

Or *********************
//Pointer to a pointer method
void create(Bclass ** ptr){
box.push( new Bclass() );
(*ptr) = box.top();
box.pop();// memory is pop
assert((*ptr)); // this is fine

Another option, which is the one I recommend, is to return the pointer.
Bclass *create(void){
Bclass * ptr = NULL;
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine
return ptr;
 
P

PKH

DamonChong said:
Hi,

I am still struggling to master C++ and is trying to understand how to
achieve passing arguments using pointers. I got some questions that I
like to post to the experts here, hope you can help to clarify my
doubts. I'm using g++ version 3.3.4. I created 3 classes as below for
testing some concepts. The questions are written as comments in
Bclass.h file. Thank you for your time and tips!

------------runtime errors------------
{8=> main
Aclass created.
Bclass instantiated.
main: Aclass.h:19: void Aclass::test(): Assertion `b' failed.
Aborted


-------------file: main.cc------------
#include "Aclass.h"

int main(){
Aclass a;
a.test();
}

-------------file: Aclass.h-----------
#ifndef ACLASS_H
#define ACLASS_H

#include "Bclass.h"
#include <stack>
#include <cassert>

class Aclass{
public:
Aclass(){
std::cout << "Aclass created." << std::endl;
}
~Aclass(){ std::cout << "Aclass destructed." << std::endl; }

void test(){
Bclass *b=NULL;
if( box.empty() ){
create(b);
assert(b); // As expected this fails during runtime
/* Qn: Is the failure because pointer 'b' is pointing to NULL?
* Qn: Is the reason why the call to "create" function without effect
* because the local pointer 'ptr' was changed to point to a temporary
object?
*/
}
delete b;
}

Is should fail because b is NULL. When you call create(b), you're just
passing the address (NULL in this case) of whatever b is pointing at as a
parameter, and not b itself. It might help to think of regular variables are
just 'names' for memory-locations where the variables value are stored.
Pointers to variables are the same, only that they use their
memory-locations to store the address of another variables memory-location.

If you want b to point to the object created in 'create', you could return
the address of the new object like this:

Bclass* create(){ return new Bclass();}

or use a pointer to a Bclass pointer like this:

void create(Bclass** pptr){Bclass* ptr = new Bclass(); *pptr = ptr;} //
stores the address of the new object in b's memory location when called like
this 'create(&b);'




protected:
void create(Bclass *ptr){
box.push( new Bclass() );
ptr = box.top();
box.pop();// memory is pop
assert(ptr); // this is fine
/* Qn: Is the reason the assertion pass because local pointer 'b' is
* still referencing the memory?
* Qn: Is the memory release or considered unreferenced only if
* we get out of the "create" function?
*/
}

b has no meaning inside this function. All you know is that you got a
parameter called ptr which contains the memory address of a Bclass object.
The assertion passes because ptr is pointing at the new object. Memory
allocated with 'new' is not released automatically when you leave a
function.

PKH
 

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,770
Messages
2,569,583
Members
45,074
Latest member
StanleyFra

Latest Threads

Top