Math Is Fun Forum
  Discussion about math, puzzles, games and fun.   Useful symbols: ÷ × ½ √ ∞ ≠ ≤ ≥ ≈ ⇒ ± ∈ Δ θ ∴ ∑ ∫ • π ƒ -¹ ² ³ °

You are not logged in.

#1 2007-07-31 06:09:12

mikau
Member
Registered: 2005-08-22
Posts: 1,504

C++: pointers, references and memory leaks

I have a few questions about pointers, reference variables and memory leaks,
and since this is such an infamous topic in C++ i thought it would be a good idea to have a thread to discuss it.

One question here is this, lets say you want a function/method of a class Dog that creates a Dog object, but is n ot a constructor. What is the best way to do this?

1. You can create a method makeDog()

Dog makeDog()
{
    Dog myDog("Pokey", 4); // name, age
    return myDog;
}

that works but when the function returns, a member wise copy must be made,
and that is costly and inefficient.

2. You can return a reference

Dog &makeDog()
{
    Dog myDog("Pokey",4);
    return myDog; // no good
}

that doesn't even work becuase you're attempting to return a reference to an object thats destroyed as soon as the method ends.

3. You can declare the object on the freestore and return the adress

Dog* makeDog()
{
    Dog *myDog = new Dog("Pokey", 4);
    return myDog;
}

which works, okay, though the function must be asssigned to a pointer when called.

4. You can also return a reference to the object on the freestore

Dog & makeDog()
{
    Dog *myDog = new Dog("Pokey", 4);
    return *myDog;
}

that works but in order to ensure that the Dog object on the freestore is eventually deleted, you need to assign this function's return value to either a pointer (in which case the above method makes more sense) or a reference. However, to delete the Dog object on the freestore you must make a pointer to the references adress, and then call delete. (ugly!) another potential problem is, what does the reference now refer to if it doesn't immediatly go out of scope?

5. And the last method (that I know of) is to pass a dog object into the method to be molded as desired

Dog& makeDog(Dog & myDog)
{
     myDog.setAge(4);
     myDog.setName("Pokey");
     return myDog;
}

of course, MakeDog is kind of a dumb name for the last method but you get the idea.

So which way is correct? 3 and 5 seem like the best and 5 looks like it could serve 3's purpose by declaring a freestore object before passing it into the function, however, is there ever a case where 3 or some other method would be smarter?

I have a few other questions but one at a time.


A logarithm is just a misspelled algorithm.

Offline

#2 2007-07-31 08:39:17

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

Note that you need not have any return value in (5).

There is no correct solution.  It depends on the project.  (3) has a pitfall because you are risking memory leaks.  Typically, you want the same function which allocates memory to be the one that deallocates memory.  A better version of (3) is:

void makeDog(Dog *d)
{
    d->setAge(4);
    d->setName("Pokey");
}

Which is the equivalent of makeDog(*d) in (5), with d being a pointer.  My code above can also be called with makedDog(&d), d not being a pointer.

In general, 5 is preferred because a function like this should manipulate data, not manage it.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#3 2007-08-01 01:51:36

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

Okay, that makes sense. Thanks!

Next question. My book wasn't exceedingly clear on this point.

When you say

Dog pokey = sparky;

assuming you haven't overloaded the assignment operator, the copy constructor is used, but if you do overload the assignment operator, whatever you told it to do will happen. The question is, in how many places does overloading the assignment operator change where the copy constructor would normally be called?

If for instance you have a method like

Dog makeDog()
{
    Dog myDog("Pokey", 4);
    return myDog;
}

if i'm not mistaken, i believe room is made for a dog object where you call the function, and this Dog object is assigned to the return value, which in this case requires a copy be made. But, is the copy made by way of the assignment operator's new definition, or just the copy constructor?

Last edited by mikau (2007-08-01 02:01:12)


A logarithm is just a misspelled algorithm.

Offline

#4 2007-08-01 05:06:06

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

assuming you haven't overloaded the assignment operator, the copy constructor is used, but if you do overload the assignment operator, whatever you told it to do will happen. The question is, in how many places does overloading the assignment operator change where the copy constructor would normally be called?

No, here the copy constructor is being called.  When I was learning all this, I made a very simple class:

#include <string>
#include <iostream>

using namespace std;

class Dog {
public: 
  Dog() {
    cout << "Entering default constructor." << endl;
    age = 0;
    name = "noname";
    cout << "Leaving default constructor." << endl;
  }
  Dog(int Age, string Name) {
    cout << "Entering constructor(int, string)." << endl;
    age = Age;
    name = Name;
    cout << "Leaving constructor(int, string)." << endl;
  }
  Dog(Dog &d) {
    cout << "Entering copy constructor." << endl;
    this->age = d.age;
    this->name = d.name;
    cout << "Leaving copy constructor." << endl;
  }
  Dog & operator = (Dog &d) {
    cout << "Entering assignment operator." << endl;
    this->age = d.age;
    this->name = d.name;
    cout << "Leaving assignment operator." << endl;
    return *this;
  }
  ~Dog() {
    cout << "Entering deconstructor." << endl;
    cout << "Leaving deconstructor." << endl;
  }
  int age;
  string name;
};

int main() {
  Dog sparky(4, "sparky");
  Dog pokey = sparky;
  return 0;
}

The output for this code is:

Entering constructor(int, string).
Leaving constructor(int, string).
Entering copy constructor.
Leaving copy constructor.

Of course, you may wish to make it more verbose, but that's the basic idea.  Helped me a lot in finding out what certain things were calling.

if i'm not mistaken, i believe room is made for a dog object where you call the function, and this Dog object is assigned to the return value, which in this case requires a copy be made. But, is the copy made by way of the assignment operator's new definition, or just the copy constructor?

Assuming that your code is:

Dog d;
d = makeDog();

Oddly enough, both.  First, in order to have a return value, a copy of myDog is made and pushed on the execution stack (don't worry if you don't know what this is).  Then myDog is destroyed.  Then this copy is assigned to d.

The code:

Dog makeDog()
{
    Dog myDog(4, "Pokey");
    return myDog;
}

int main() {
  Dog d;
  d = makeDog();
  return 0;
}

Produces:

Entering default constructor.
Leaving default constructor.
Entering constructor(int, string).
Leaving constructor(int, string).
Entering copy constructor.
Leaving copy constructor.
Entering deconstructor.
Leaving deconstructor.
Entering assignment operator.
Leaving assignment operator.
Entering deconstructor.
Leaving deconstructor.
Entering deconstructor.
Leaving deconstructor.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#5 2008-01-07 17:19:36

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

hey here's another question. I was reviewing my C++ book and i found this function declaration

const Cat * const function1(const Cat* const theCat);

does this declaration make ANY sense at all? okay, the fact that the parameter is a constant pointer to a constant cat is fine, the cat won't be changed, and the pointer will not be changed within the function. Its also fine that the pointer returns a pointer to a constant cat so you can't do something like function1(&myCat)->setAge(5); but the fact that it returns a constant pointer (that can't be redirected) isn't that useless? its not like we're going to say

function1(&myCat) = &otherCat;

that wouldn't work even if it was NOT constant, right?

does that make any sense ever?


A logarithm is just a misspelled algorithm.

Offline

#6 2008-01-07 19:41:46

luca-deltodesco
Member
Registered: 2006-05-05
Posts: 1,470

Re: C++: pointers, references and memory leaks

no, that declaration is fine. However it can ofcourse only be used in one fashion:

const Cat * const pt1 = &someConstCat;
const Cat * const pt2 = function1(...);

because you are initliasing pt2 to the return of function1 its ok, you are not changing anything because it is still undefined.

I have however only made one use of a const pointer to const data once outside of a function paramater tongue

Last edited by luca-deltodesco (2008-01-07 19:44:34)


The Beginning Of All Things To End.
The End Of All Things To Come.

Offline

#7 2008-01-07 21:09:22

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

are you sure? try the following:

definition of my function:

const Cat* const myFunction(const Cat* const otherCat)
{
  return otherCat;

}

now try this:

  Cat friskey;
  const Cat * someCat = myFunction(&friskey); // not a constant pointer!
  someCat->meow();

that compiled and ran without so much as a warning from my compiler. If I don't declare the pointer someCat to be a pointer to a constant Cat it won't compile, but thats all. 

I don't see why the compiler would care. So what if someCat can point to something else later?
this brings me back to my hazy understanding of how function returns work. As far as I understand, when you call a function, it creates a variable of its exact return type in place of where it was called and when the function returns, the value is copied from whatever is returned. So in a certain sense, its like saying:

const Cat* const returnValue = myFunction(); // return value is copied back into the calling function
const Cat* otherPointer = returnValue;

and why should this be bad? (note, this also compiles for me) all we said about returnValue is that its a pointer, it has an adress and that should not hold any other adress. I don't think that says anything we assign this to must not hold any other adress either.

Likewise we can say const int x = 5;
int y = x;

y is not constant, but who cares?

But do tell me if that compiles for you, Id like to know.

Last edited by mikau (2008-01-07 21:34:01)


A logarithm is just a misspelled algorithm.

Offline

#8 2008-01-07 22:32:56

luca-deltodesco
Member
Registered: 2006-05-05
Posts: 1,470

Re: C++: pointers, references and memory leaks

const Cat* const myFunction(const Cat* const otherCat)
{
  return otherCat;
}

Cat friskey;
const Cat * someCat = myFunction(&friskey);
someCat->meow();

that shouldn't compile, what compiler are you using that allows it? Why shouldn't that compile? Because &friskey returns a pointer of type 'Cat *' whereas the function argument is for a pointer of type 'const Cat * const' and also because you are assigning the return to a different type of pointer aswell, which also has a knock on effect because someCat->meow() should not be allowed unless it is a const function which you didn't specify.This however is perfectly valid.

class Cat
{
public:
  void Cat() {}
  void meow() const {}
};

const Cat* const myFunction(const Cat* const otherCat)
{
  return otherCat;
}

int main()
{
  const Cat friskey;
  const Cat * const someCat = myFunction((const Cat * const)&friskey);
  someCat->meow();
  return 0;
}

remember that C++ is very strict, or is meant to be atleast.

Last edited by luca-deltodesco (2008-01-07 22:35:36)


The Beginning Of All Things To End.
The End Of All Things To Come.

Offline

#9 2008-01-08 07:30:36

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

You are allowed to cast off constant pointers, even implicitly.

remember that C++ is very strict, or is meant to be atleast.

No, that's Java.  C++ is meant to allow you to shoot yourself in the foot in as many ways as you please.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#10 2008-01-08 07:38:47

luca-deltodesco
Member
Registered: 2006-05-05
Posts: 1,470

Re: C++: pointers, references and memory leaks

ive never shot myself in the foot before tongue (although i have stepped on it a few times)


The Beginning Of All Things To End.
The End Of All Things To Come.

Offline

#11 2008-01-08 08:55:10

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

I knew it!

So would you agree then, Ricky, that declaring the return value to be a constant pointer is pointless? (sorry, bad pun)

Luca, again I'm inclined to point out that this is perfectly legal:

const int x = 5;
int y = x; // y is not constant

I think the purpose of declaring a pointer constant in a parameter list is to ensure that the parameter does not change within the body of the function. Moreover, when we declare the parameter to be a pointer to a constant object, we don' do this to ensure only a constant object is passed in, we merely do it to ensure no changes are made to the actual object within the body of the function.  It doesn't care if the object passed in is constant or not, it treats it as constant within the function.

Last edited by mikau (2008-01-08 09:28:34)


A logarithm is just a misspelled algorithm.

Offline

#12 2008-01-08 09:29:13

luca-deltodesco
Member
Registered: 2006-05-05
Posts: 1,470

Re: C++: pointers, references and memory leaks

however ricky, it is in error to do what he did because the pointer although it may not matter if the pointer itself is const in this case, it still has to point to a const Cat to be accepted atleast with my compiler, and that makes perfect sense


The Beginning Of All Things To End.
The End Of All Things To Come.

Offline

#13 2008-01-08 09:30:42

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

didn't my pointer point to a const Cat?


Cat friskey;
const Cat * someCat = myFunction(&friskey); // someCat is a pointer to a constant cat
someCat->meow(); // yes meow is a constant function

are you saying its bad to pass in '&friskey' as a parameter because its not a pointer to a constant cat? my book explicitly states this ability as not only legal but useful. If your compiler doesn't allow this, well...thats WEIRD!

Last edited by mikau (2008-01-08 09:47:14)


A logarithm is just a misspelled algorithm.

Offline

#14 2008-01-12 20:21:18

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

I'm having some trouble figuring out how to make pointers to multidimensional arays. It was not explained in my book and my googling only produced a host of different solutions, some of which don't even work.

Anyway here's the problem:

here we create a pointer to a regular array

int * list = new int[10];

we merely create a pointer to the element type and assign the array to it. Easy and clean.

however,

int* list = new int[2][5];

this will not compile. neither will

int array[3][2];

int * list = array[2][0]; // this, or
int * list = array[0]; // this, or
list * list = array; // this

i saw someone claiming you needed pointers to pointers

int** list = new int[3][2]; // wouldn't compile

in the end I found the following works:

int (* list)[2] = array;

you can now use 'list' just as you would 'array', but the issue is, this oddly syntaxed declaration (which requires the parens) creates some sort of array of length 2, and this length must be determinable at compile time. This means you couldn't, for instance, dynamically set the size of the array at run time. to do that we need to put these on the freestore. But how do we do that?

my best guess was:

int (*) * list = new int(*)[size];

of course, THAT doesn't compile. so how on earth do we do this?

I wish i could find a good explanation of how C++ deals with multidimensional arrays internally and how the pointers work with them.

Last edited by mikau (2008-01-12 20:26:37)


A logarithm is just a misspelled algorithm.

Offline

#15 2008-01-12 21:11:37

luca-deltodesco
Member
Registered: 2006-05-05
Posts: 1,470

Re: C++: pointers, references and memory leaks

seriously what compiler are you using?

int array[3][2]; is perfectly fine.

if you want to use the new operator, under my compiler you have to do

int ** arrs = (int**)new int [4][5];

but be careful, because if you do

delete [] arrs;

you will get memory leaks, as it will only delete the list of pointers to the second set of arrays. you have to do

for(int i = 0; i<4; i++)
   delete [] arrs[i];
delete [] arrs;

Last edited by luca-deltodesco (2008-01-12 21:16:50)


The Beginning Of All Things To End.
The End Of All Things To Come.

Offline

#16 2008-01-12 22:35:33

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

sorry i could have written that better, int array[3][2] does compile, i was just using that to show what the original array was before trying to create a pointer to it.

So you are casting the array as a pointer to a pointer, eh..hmm

well i just tried this:

  int array[5][4];

  array[1][1] = 6;  

  int ** matrix = (int**) array; // casting to an int pointer pointer

  std::cout << " matrix[1][1]: " << matrix[1][1] << "\n"; // should print 6

output: matrix[1][1]: 4214504

thats not good. I know your example was on the freestore but it should work here too, right?

and I'm using Borland C++ Builder X, released in 2003 it seems.

(edit) and how do you pass multi-d arrays as arguments to functions? do you just cast them? personally i don't mind doing that but its not exactly elegant.

Last edited by mikau (2008-01-12 22:45:35)


A logarithm is just a misspelled algorithm.

Offline

#17 2008-01-13 07:24:12

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

It's probably much better style to do this instead:

(int *) *matrix = new int[rows];
for (i = 0; i < rows; i++) {
  matrix[i] = new int[cols];
}

Also, this code will let you create a ragged array.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#18 2008-01-13 08:32:46

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

I agree thats much cleaner and understandable. Shouldn't it be this though?

(int *) *matrix = new int* [rows]; // array of pointers
for (i = 0; i < rows; i++) {
  matrix[i] = new int[cols]; // defrerence the pointer and set it to point to the new array
}

also in the first line, did you add those parens in '(int *)' just for clarity or for another reason.

This works pretty nicely but if you wanted to create arrays of higher dimension, it would start to get pretty ugly, wouldn't you say?

Last edited by mikau (2008-01-13 08:44:28)


A logarithm is just a misspelled algorithm.

Offline

#19 2008-01-13 12:51:59

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

This works pretty nicely but if you wanted to create arrays of higher dimension, it would start to get pretty ugly, wouldn't you say?

Yes, it would be.  That is, unless you used OO programming.  Then what you have is an array class, a matrix class is an array of an array, and a cube is an array of matrices, and so on.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#20 2008-01-13 13:18:02

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

i agree a matrix is like an array of arrays, but C++ does not seem to agree in terms of syntax.
For instance, you can't just say:

int matrix[3][2];

int * array1 = matrix[1];
int * array2 = matrix[2];

i may have it backwards (requiring 3 array pointers instead of 2) but you get the idea. neither work, and other variations like adding [0] at the end don't work.

Does Luca's suggestion work for you, Ricky? doesn't seem to work properly for me.


A logarithm is just a misspelled algorithm.

Offline

#21 2008-01-14 01:09:42

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

Check out the STL, specifically the vector class, if you wish to take the "naive" view that a matrix is an array of arrays.  I say naive because in reality, there needs to be two different types of data, pointers and values, inside such a matrix.

vector<vector<int> > matrix;


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#22 2008-01-14 01:16:36

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

Just to add on to my last post, memory and hard drive are both shaped like arrays (hard drive is a bit more complicated, lets not go there).  So it is very natural to define an array.  However, there is absolutely no way you can expect it to behave like a matrix.  Rather, additional structure needs to be defined to get this behavior, and this is where the pointers come in.


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#23 2008-01-15 11:26:35

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

Check out the STL, specifically the vector class, if you wish to take the "naive" view that a matrix is an array of arrays.

Hold it! I DON'T want to take that view! In fact, stating that a 2 dimensional array is an array of arrays always made me uncomfortable based on syntax and how the compiler treats it.

Last edited by mikau (2008-01-15 11:27:10)


A logarithm is just a misspelled algorithm.

Offline

#24 2008-01-15 12:54:37

Ricky
Moderator
Registered: 2005-12-04
Posts: 3,791

Re: C++: pointers, references and memory leaks

i agree a matrix is like an array of arrays, but C++ does not seem to agree in terms of syntax.

?

A matrix is an array of arrays, but this view is naive because you can't just say to your computer, "Make me an array of arrays".  You need to define more structure behind it.  OO programming allows you to do this very naturally:

vector<vector<int> > matrix;


"In the real world, this would be a problem.  But in mathematics, we can just define a place where this problem doesn't exist.  So we'll go ahead and do that now..."

Offline

#25 2008-01-16 16:49:02

mikau
Member
Registered: 2005-08-22
Posts: 1,504

Re: C++: pointers, references and memory leaks

whoops! i thought i replied to this.

i meant to say a 2 dimensional array in C++ is not an array of 1 dimensional arrays in C++, instead it seems to be stored and handled differently.

Am I not correct?


A logarithm is just a misspelled algorithm.

Offline

Board footer

Powered by FluxBB