0

I read on a similar question on here that passing by value will create a local copy of the object in your function. When I try to do this, my original object gets altered, but I do not want it to change.

The goal of this test was to try and pass an object, to alter it locally, but leaving the original untouched.

In the ObjectList header file:

int **board;

ObjectLise class containing a constructor and a print function:

ObjectList::ObjectList()
{
    board = new int*[9];
    for(int i = 0; i < 9; i++)
    {
        board[i] = new int[9];
    }

    for(int i = 0; i < 9; i++)
    {
        for(int j = 0; j < 9; j++)
        {
            board[i][j] = 10;
        }
    }
}

void ObjectList::printB()
{
    for(int i = 0; i < 9; i++)
    {
        for(int j = 0; j < 9; j++)
        {
            cout << board[i][j] << ",";
        }
        cout << endl;
    }
}

ChangeBoard class with function that gets passed an ObjectList.

void ChangeBoard::LetsChange(ObjectList layout)
{
    layout.board[0][0] = 99;
    layout.board[1][0] = 99;
    layout.board[2][0] = 99;
    layout.board[3][0] = 99;
    layout.board[4][0] = 99;
    layout.board[5][0] = 99;
}

In the main I create both objects and pass the ObjectList object to the LetsChange function to try and only alter the object locally, that is in the function only:

ObjectList object = ObjectList();

ChangeBoard change = ChangeBoard();

object.printB();

change.LetsChange(object);
cout << endl;

object.printB();

The output shows that the original object gets altered:

10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,

99,10,10,10,10,10,10,10,10,
99,10,10,10,10,10,10,10,10,
99,10,10,10,10,10,10,10,10,
99,10,10,10,10,10,10,10,10,
99,10,10,10,10,10,10,10,10,
99,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
10,10,10,10,10,10,10,10,10,
MilkyCode
  • 25
  • 8
  • 4
    The *object* isn't modified, but the data *pointed to* by `board` will be modified. I suggest you read about [the rules of three, five and zero](http://en.cppreference.com/w/cpp/language/rule_of_three), and stop using pointers for arrays or vectors. – Some programmer dude Sep 25 '17 at 09:00
  • 3
    Your question lacks a [mcve], but it looks like `ObjectList`'s copy-constructor is broken. – Quentin Sep 25 '17 at 09:01
  • Voted to close as lacking reproducible example. – Cheers and hth. - Alf Sep 25 '17 at 09:02
  • Assuming you haven't explicitly defined one, I think you need to look up copy constructor behaviour http://en.cppreference.com/w/cpp/language/copy_constructor – zeFrenchy Sep 25 '17 at 09:05
  • As far as I understand you can only return pointers to arrays and not static arrays. This is why I chose to go with pointers. – MilkyCode Sep 25 '17 at 09:06
  • @zeFrenchy. If I write a copy constructor that makes a deep copy of the board variable will this code produce what I initially wanted? – MilkyCode Sep 25 '17 at 09:08
  • Should be ... see my answer below. :) – zeFrenchy Sep 25 '17 at 09:09

4 Answers4

2

Without a copy-constructor that actually copies the memory (or a suitable standard container) what happens when you pass the object by value is that the pointer member board is copied. The pointer is copied, not the data it points to. It's a so-called shallow copy, not a deep copy.

That means in the ChangeBoard::LetsChange function you have two objects in which the board members are both pointing to the same location. A quick printout of the board member or by just using a debugger you should have seen this very quickly.

In the function you modify the memory pointed to by this board pointer, not the data of the object itself. If you did e.g. layout.board = new int*[9]; in the function, you would modify the actual member, and that change would not be reflected back in the calling function.


This copying of the pointer can lead to undefined behavior if you have a destructor that delete[] the memory pointed to by board. Because then you will free the memory for both objects, and when you later use the board member in the original object it will no longer point to allocated data.

This is the reason you need to consider the rules of three, five and zero.

I recommend you stop using pointers and instead use either std::array if the size is a compile-time constant, or std::vector if the size is set at run-time.

Using either std::array or std::vector you can use the rule of zero and not have to worry about handling your own memory, copying and deleting.

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
1

The implicit copy constructor will copy the content of the board pointer when copying the object ... so it will still point at the data from the original object. An explicit copy constructor would probably need to allocate and copy the board array to obtain the behaviour you expect.

zeFrenchy
  • 6,541
  • 1
  • 27
  • 36
0

As others have mentioned your examples is not full

But let me try to clear a bit.
Your object object is passed by value, e.g. LetsChange function call makes a local copy of your object e.g. its members.

In your case, board which I suppose is a member of your class ObjectList will be copied but not the allocated memory, to which you point by board.

Therefore when you modify the memory it will technically "affect" the object you have.

deimus
  • 9,565
  • 12
  • 63
  • 107
0

It seems you do not provide a copy constructor. The default copy constructor simply copies every member of the object (if this operation is define for every member of course). A copy of board is created. The copy of a pointer points to the same data as the original, though. So you are altering the original data which is technically not part of any object through a copy.

You could always resolve this by writing a copy constructor that copies the data being pointed to. A much better solution is to get rid of the new and corresponding delete statements and replace with a more appropriate alternative.

Most people would use std::vector. It will fix your default copy constructor and move constructor. It is also a variable length array which you might find useful.

If you need to enforce a static size, std::array is pretty much a safer, copyable C-style array. It doesn't decay to a pointer and it provides a proper copy constructor.

Lastly, if you need a static array but on the heap for whatever reason, std::unique_ptr<> and std::shared_ptr<> can hold an array. What they do is manage the lifetime of your objects internally. The difference is that unique_ptr only allows passing of ownership while shared_ptrs can point to the same object and they make sure to clean-up when the last pointer is destroyed or reset.

patatahooligan
  • 3,111
  • 1
  • 18
  • 27