views:

211

answers:

6

I tried an example live below:

typedef struct point
{
    int x;
    int y;
} point;

    void cp(point p)
    {
        cout<<p.x<<endl;
        cout<<p.y<<endl;
    }

    int main()
    {

        point p1;
        p1.x=1;
        p1.y=2;
        cp(p1);
    }

The result thats printed out is:

1
2

which is what I expected. My question is: Does parameter p get the full copy of object p1? If so, I wonder if this is a good practice? (I assumed when the struct gets big in size, this will create a lot of copy overhead).

+15  A: 

Yes, there's nothing wrong with this and yes, p is a complete copy of p1. I wouldn't call a struct with two ints large, but if the struct does get large and if you don't need to alter it in the function body you could consider passing it by const reference:

void cp(const point& p)
{
    // ...
}
Charles Bailey
A: 
void cp(point p){
}

gets it by value

void cp(point *p){
}

gets it by reference

Just like any other data variable.

In java the scenario is different. Passing objects always go by reference.

Kasturi
`point *` is by pointer, rather than by reference. As this is a C++ question it's a significant difference.
Charles Bailey
@charles Agreed. My bad
Kasturi
Java is actually pass-by-value, though that's another question ;)
Nick Meyer
A: 

In you case the point struct is passed "by value" meaning, that the whole structure is copied. For big data types, this can indeed be slow.

You can consider passing the object by reference

void cp(point& p) // p may be altered!

or be const reference

void cp(const point& p) // p may not be altered!
Danvil
A: 

See the possibilities to avoid passing objects by value. The object is not just 'copied', but is copy constructed. So, this involves calling copy constructor and the chain of copy constructors if your object is composed or derived of more objects. Pass by reference if possible.

void cp(point &p const) const {

    cout << p.x << endl;
    cout << p.y << endl;

}

Kiran
Roddy
David Thornley
I wouldn't recommend always passing by reference. There is a trade off and it's not always clearly in favour of by reference. The fact that references may refer to global object means that there are optimizations that can't be made in the function body which might be performed with copied parameters. Copying can be very cheap (there are no copy-constructors in this case and depending on the calling convention the 'copy' might just be a load into registers.
Charles Bailey
Sorry for the mistake guys. I agree with the comments on constant. The stress on references is for the composed objects which may result in multiple constructions. In this case, yes I agree that pass by value may optimize better.
Kiran
A: 

Before I give an answer to your question (you find it at the end of this post), here's a brief summary of the possibilities you have for passing arguments to a function:


1. Copy-constructed objects (pass-by-value):

void cp(point p);

This is pass-by-value. A temporary point object is created and copy-constructed from whatever point object you pass into cp. Once execution leaves the cp function, the temporary object is destroyed.

Note that because the function operates on a copy of whatever was passed to the function, you can modify that local point object as much as you want, the original object of the caller will not be affected. There's no way to change this behaviour with pass-by-value parameters.


2. References to objects (pass-by-reference):

void cp(point& p);

This is pass-by-reference. The actual object passed to the function is available (and potentially subject to modification) inside the function. If you don't want the function to be able to change the passed-in object, declare the parameter as const point&:

void cp(const point& p);

3. Pointers to objects (pass-by-reference):

void cp(point* p);

This is also pass-by-reference, with a few subtle differences. One notable difference is that you can pass a null pointer to the function. This is not possible with references, because references must be initialized and cannot be reseated afterwards. -- As with references, if you want to disallow cp from changing the passed-in point, declare it as const:

void cp(const point* p);

Answer to your question:

Pass-by-value parameters are not inherently bad in any way. Of course, there are types for which copy construction is expensive (e.g. very large or complex objects), or where it has certain side effects (e.g. with std::auto_ptr). In these cases, you should be careful. Otherwise, it's just another feature of C++ which has its perfectly reasonable uses.

stakx
+1  A: 

There is nothing wrong with passing structs as parameters. Everything is passed by value in C++ so a full copy is indeed made.

The struct you gave in your example is small so it's probably not a problem if you pass it by value. But if you work with bigger data structures, you may want to pass it by reference.

Beware though, passing by reference means that if you modify the struct inside your function, your original struct will be modified. Be sure to use the const keyword in every case where you don't modify the struct. This will give you an immediate information about if your functions do modify the information or not.

Your example could be modified to work with references this way :

typedef struct point
{
    int x;
    int y;
} point;

void cp(const point& p) // You can know that cp doesn't modify your struct
{
    cout<<p.x<<endl;
    cout<<p.y<<endl;
}

void mod_point(point& p) // You can know that mod_points modifies your struct
{
    p.x += 1;
    p.y += 1;
}

int main()
{
    point p1;
    p1.x=1;
    p1.y=2;
    cp(p1);
    mod_point(p1);
    cp(p1); // will output 2 and 3
}
raph.amiard
Not everything is passed by value in C++, though this is the case in C (which doesn't have references).
Nick Meyer
Well in function declarations, everything is passed by value unless you specify so. This is very different from most modern languages in which objects are passed automatically by reference. Though, you can pass a parameter by reference to a function without knowing it because the semantics are the same.
raph.amiard