1

I'm a java programmer switching over to C++. I have a list of data in a class. I want to return the contents of a list stored in a class variable and then generate a new list and store it in the class variable so I can start adding new data to the empty list. I think I know how to do it, but I want to double check since I'm new to references and c++ memory management and don't want a stupid memory leak later. (note, I can't copy my actual code easily so I'm just rewriting it, forgive me if I mistype anything).

I believe the correct syntax would be something like this:

//mylist is typedef of a list type
mylist& temporaryList=classList;
classList=myList();
return classList;

Is this syntax correct? Also, will I have to worry about freeing either the returned variable or the classList variable at any time or will RIAA take care of it all for me?

Sorry for asking such an easy question, but thank you for confirming my assumptions.

Ernest Friedman-Hill
  • 80,601
  • 10
  • 150
  • 186
dsollen
  • 6,046
  • 6
  • 43
  • 84
  • I have a striking suspicion you might not have looked too deeply into pointers vs references. Forgive me if you have, but [this question](http://stackoverflow.com/questions/57483/what-are-the-differences-between-pointer-variable-and-reference-variable-in-c) explains them really well. – chris Jun 16 '12 at 00:26

3 Answers3

2
mylist& temporaryList=classList;

tempraryList is a reference. When you change classList, it will change too. Try this:

mylist tempraryList = classList;

This will copy mylist's copy constructor, creating a new one instead of just aliasing the other one.


return classList;

This is returning the one you just decided should be a new list. You want to return temporaryList. Make sure it isn't being returned by reference, though, because temporaryList will go out of scope (cleaning itself up, since it was allocated on the stack) and you'll end up with a dangling reference.

As well, usually, rather than assigning the result of a default constructor, classes might provide a sort of reset function to do that without the overhead of another object.

chris
  • 60,560
  • 13
  • 143
  • 205
1

As @chris points out you have a problem in that you are using a reference, references have the nice feature that they alias the actual object at little to no cost, but in your case it means that when you reset the member list you are resetting the only list in your program.

The trivial naïve fix to your code is, as @chris also points out, to copy the list and then reset the original:

mylist getAndClear() {
   mylist temporaryList=classList;    // make a copy
   classList=myList();                // reset the internal
   return temporaryList;              // return the **copy**
}

Now, the problem with this approach is that you are incurring the cost of copying when you know that the original list is going to be destroyed immediately. You can avoid that cost by using the copy-and-swap idiom(*):

mylist getAndClear() { mylist tmp; // empty swap( tmp, classList ); // swap contents, now classList is empty // tmp holds the data return tmp; }

This is assuming that mylist is a std::list. If it is not, make sure that you implement swap (or in C++11 move constructors, that will enable an efficient std::swap).


(*) While this may not seem a direct application of the copy-and-swap idiom, it actually is, where the modification to be applied is clearing the list. Perform a copy and apply the change over the copy (in this case the copy is avoided, as the change is emptying it), then swap the contents once the operation has completed successfully.

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • Thank you. I was trying to use aliasing to avoid the swap, but looking back at this today (instead of when I was half asleep on friday) it's pretty obvious why my syntax was wrong. I had assumed swap was more...niave in the way it did it's swap (ie, it didn't make use of the function pointer to avoid unnessesary copying of data within the list nodes). Now that I think of it that was pretty foolish of me, I should have realized that a C function like this would work to avoid unnessesary copying when it did a swap. Efficency is sort of the entire reason C even exists any more after all. – dsollen Jun 17 '12 at 21:43
0

chris mentions using a member function to reset or clear the object like this:

mylist tmp = classList;
classList.clear();
return tmp;

But you can usually do even better by avoiding the copy in the first place.

mylist tmp;
std::swap(tmp,classList);
return tmp;

Also, will I have to worry about freeing either the returned variable or the classList variable at any time or will RIAA take care of it all for me?

You don't need to delete resources unless you new them somewhere. And if you do use new then you should also use smart pointers so you still won't have to delete anything.

One of the most important things to understand about C++ coming from Java is that C++ objects are value-like objects by default. That is:

class A {
    bool bar_called;
public:
    A() : bar_called(false) {}
    void bar() { bar_called = true; }
    bool has_bar_been_called_on_this_object() { return bar_called; }
};

void foo(A a) {
    a.bar();
}

int main() {
    A a;
    foo(a);
    std::cout << a.has_bar_been_called_on_this_object() << '\n';
}

The output will indicate that bar has not been called on a. Java uses, but tries to hide, pointers. So once you figure out pointers in C++ things should make more sense to you, and then you will be able figure out how to not use pointers.

Object o = new Object(); // Java hides the fact that o is a pointer to an Object, but fails to hide the consequences
Object b = o; // b is a pointer to an object, the same Object o points to.

// Equivalent C++
Object *o = new Object();
Object *b = o;

Judging from the C++ code you presented, in Java you'd do what your asking about something like this:

mylist tmp = classList;
classList = new mylist();
return tmp;

The equivalent in C++ would be:

mylist *tmp = classList; // classList is a pointer to a new'd up list.
classList = new mylist();
return tmp;

However that's not idomatic C++. In C++ you generally don't want to use pointers, and if you do you want to use smart pointers

std::shared_ptr<mylist> tmp = classList; // classList is a std::shared_ptr<mylist>
classList = std::make_shared<mylist>();
return tmp;

or

std::unique_ptr<mylist> tmp = std::move(classList); // classList is a unique_ptr
classList = std::unique_ptr<mylist>(new mylist()); // careful here, don't go calling a bunch of functions inside the mylist initializer, it's dangerous for reason beyond the scope of this post
return tmp;

But the C++ way is really to avoid pointers altogether.

mylist tmp; // classList is not a pointer at all
std::swap(tmp,classList); // the values of classList and tmp are swapped
return tmp; // tmp is returned by value, tmp has the same value as classList, but is not the same object, tmp and classList are objects, not pointers to objects as they are in Java or in the above C++ examples.
bames53
  • 86,085
  • 15
  • 179
  • 244