SuhDude555
SuhDude555

Reputation: 1

C++ returning object created on heap and modifying it, doesnt change it?

I have following code

#include <iostream>
#include <vector>
using namespace std;

struct foo {
    struct bar {
        int foobar;
    };

    vector<bar*> barp;

    bar & insert(int v){
        bar * b = new bar();
        (*b).foobar = v;
        barp.push_back(b);
        return *b;
    }

    void edit(bar & b, int v){
        b.foobar = v;
    }
};

int main() {
    foo f;
    foo::bar b = f.insert(5);
    f.edit(b, 10);
    std::cout << (b.foobar == 10?"true":"false") << std::endl;//now ok
    std::cout << (b.foobar == 5?"true":"false") << std::endl;//now ok
    std::cout << ((*f.barp[0]).foobar == 10?"true":"false") << std::endl;//after edit, still returns false
    std::cout << ((*f.barp[0]).foobar == 5?"true":"false") << std::endl;//after edit, returns true
    return 0;
}

Could someone explain me, why doesnt the "b.foobar" change to 10? Doesnt the b have the same address as the one saved in f.barp[0]?

EDIT:Thanks for answers, adding reference to void edit(bar & b, int v) does, of course, make sense. However adding reference to "bar & insert" doesnt seem to change anything, as the (*f.barp[0]).foobar stays unchanged after edit, even though insert should return reference now.

Upvotes: 0

Views: 64

Answers (4)

skgbanga
skgbanga

Reputation: 2667

foo::bar b = f.insert(5);

This b object is different from *f.barp[0] since it is created from returned reference. To make this work, change this line to

foo::bar& b = f.insert(5);

That way you are creating a reference to the object which you just inserted in the vector.

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726489

Doesn't the b have the same address as the one saved in f.barp[0]?

No, it does not. You return the object by value from the insert, i.e.

bar insert(int v)
^^^

Returning by value implies a copy: a new bar is constructed using a copy constructor, and the original one is discarded*.

To get the results that you expect, return bar& from insert:

bar& insert(int v) {
// ^
}

Similarly, edit should take its parameter by reference if you would like all functions to work on the same object.

* If it were not for you storing the pointer in a collection, this would also create a memory leak. Your program does have memory leak, too, but you can fix it by deleting objects in the barp vector.

Upvotes: 3

zwol
zwol

Reputation: 140495

Doesnt the b have the same address as the one saved in f.barp[0]?

No, it does not. Every time you use bar with no further qualifications as an argument or return type, you are asking for a copy to be made. In this case, that means both the variable b in main and the variable b in edit are copies.

For this toy example, you can make the program do what you expected with these changes:

- bar insert(int v){
+ bar &insert(int v){

- void edit(bar b, int v){
+ void edit(bar &b, int v){

- foo::bar b = f.insert(5);
+ foo::bar &b = f.insert(5);

If you do not understand what that does or why, please consult a C++ textbook for an explanation of "references".

(If you've never seen the above -/+ notation before, it means "replace each line marked with a minus sign with the corresponding line marked with a plus sign.")

Upvotes: 0

Sam Varshavchik
Sam Varshavchik

Reputation: 118300

Because you're passing the parameter to edit() by value, instead of by reference.

edit() ends up modifying a copy of the original object, which then immediately gets thrown away.

Also, you are returning a copy of the record from insert(), as well.

Your insert() must return a pointer, instead of a copy of the new record. You must also pass a pointer to edit(), too.

Upvotes: 1

Related Questions