Call by value vs. Call by reference

S

Saeed Amrollahi

Dear All
Hi

I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:

#include <vector>
#include <iostream>

using namespace std;
void f1(std::vector<int> v)
{
cout << "f1 called" << '\n';
for (std::vector<int>::size_type sz = 0; sz < v.size(); sz++)
v[sz] = sz;
cout << "f1 end" << '\n';
}

void f2(std::vector<int> v)
{
cout << "f2 called" << '\n';
for (std::vector<int>::size_type sz = 0; sz < v.size(); sz++)
v[sz] = sz;
cout << "f2 end" << '\n';
}

void f3(std::vector<int>* pv)
{
cout << "f3 called" << '\n';
for (std::vector<int>::size_type sz = 0; sz < pv->size(); sz++)
(*pv)[sz] = sz;
cout << "f3 end" << '\n';
}
int main()
{
vector<int> v(50000000);
f1(v);
f2(v);
f3(&v);

return 0;
}

I ran under Visual Studio 2005, Visual Studio 2008 and GCC. Is it
about some compiler switches that I should on/off? Did compilers
become more clever?

In advance, thank you for your comments.
- Saeed Amrollahi
 
R

Ron AF Greve

Hi,


I would expect you see a large difference since if you pass by value it has
to copy the whole vecor, however..

In your code the compiler might have removed the whole vector copying during
optimization since you don't do anything with it. You wouldn't notice a
difference between a program with the vector passed in and one completely
without and without assignment

Regards, Ron AF Greve

http://www.InformationSuperHighway.eu
 
S

Soumen

Dear All
Hi

I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:

#include <vector>
#include <iostream>

using namespace std;
void f1(std::vector<int> v)
{
        cout << "f1 called" << '\n';
        for (std::vector<int>::size_type sz = 0; sz < v.size(); sz++)
                v[sz] = sz;
        cout << "f1 end" << '\n';

}

void f2(std::vector<int> v)
{
        cout << "f2 called" << '\n';
        for (std::vector<int>::size_type sz = 0; sz < v.size(); sz++)
                v[sz] = sz;
        cout << "f2 end" << '\n';

}

void f3(std::vector<int>* pv)
{
        cout << "f3 called" << '\n';
        for (std::vector<int>::size_type sz = 0; sz < pv->size(); sz++)
                (*pv)[sz] = sz;
        cout << "f3 end" << '\n';}

int main()
{
        vector<int> v(50000000);
        f1(v);
        f2(v);
                f3(&v);

        return 0;

}

I ran under Visual Studio 2005, Visual Studio 2008 and GCC. Is it
about some compiler switches that I should on/off? Did compilers
become more clever?

In advance, thank you for your comments.
 - Saeed Amrollahi

Probably because your vector is empty (may be it's just holding a
pointer and few other int)and you're inserting elements inside the
function.
Try inserting elements before calling the function and call the
function 1000 times or so. Also try vector of string and let it have
all same
elements. Let me know what you find.

Regards,
~ Soumen
 
J

Juha Nieminen

Saeed said:
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:

How do you measure the speed of the program? Maybe copying that vector
is relatively so fast that you don't notice the difference. Try calling
each function in a loop to see if there's a difference.
 
A

acehreli

void f1(std::vector<int> v)
{
        cout << "f1 called" << '\n';
        for (std::vector<int>::size_type sz = 0; sz < v.size(); sz++)
                v[sz] = sz;

That is not "inserting" an element, rather assigning to an existing
one.

That is a vector with 50 million ints, not empty.
Probably because your vector is empty (may be it's just holding a
pointer and few other int)and you're inserting elements inside the
function.

That would be this code:

vector<int> v; // empty
/* ... */
v.push_back(sz); // insert

Ali
 
T

Thomas J. Gritzan

Saeed said:
Dear All
Hi

I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:
[...]
void f1(std::vector<int> v) [...]
void f2(std::vector<int> v) [...]
void f3(std::vector<int>* pv)
[...]

There is no reference. You have two function that do a call-by-value and
one that does a call-by-reference (via pointer).

Obviously, the first two shouldn't show any measurable performance
difference.
 
S

Saeed Amrollahi

Saeed Amrollahi schrieb:> Dear All
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:
[...]
void f1(std::vector<int> v) [...]
void f2(std::vector<int> v) [...]
void f3(std::vector<int>* pv)

[...]

There is no reference. You have two function that do a call-by-value and
one that does a call-by-reference (via pointer).

Obviously, the first two shouldn't show any measurable performance
difference.

Hi
Sorry for typo and confusion. I actually used reference in the code:
void f1(std::vector<int> v)
void f2(std::vector<int>& v)
void f3(std::vector<int>* pv)

Based on
 
S

Saeed Amrollahi

Saeed Amrollahi schrieb:> Dear All
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:
[...]
void f1(std::vector<int> v) [...]
void f2(std::vector<int> v) [...]
void f3(std::vector<int>* pv)

[...]

There is no reference. You have two function that do a call-by-value and
one that does a call-by-reference (via pointer).

Obviously, the first two shouldn't show any measurable performance
difference.


Hi
Sorry for typo and confusion. I actually used reference in the code:
void f1(std::vector<int> v)
void f2(std::vector<int>& v)
void f3(std::vector<int>* pv)

Based on guys' advice, I changed my simple benckmark code to better
one:

template<class T>
void f1(std::vector<T> v)
{
for (int sz = 0; sz < 1000000; sz++)
v.push_back(T());
}

template<class T>
void f2(std::vector<T>& v)
{
for (int sz = 0; sz < 1000000; sz++)
v.push_back(T());
}

template<class T>
void f3(std::vector<T>* pv)
{
for (int sz = 0; sz < 1000000; sz++)
pv->push_back(T());

}

int main()
{

vector<int> v; // empty vector

cout << "f1 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f1(v);
}
cout << "f1 end" << '\n';
v.clear();
cout << "f2 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f2(v);
}
cout << "f2 end" << '\n';
v.clear();
cout << "f3 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f3(&v);
}
cout << "f3 end" << '\n';
v.clear();

return 0;
}

I don't use a precise clock, but I expected a difference order of
magnitude efficiency but it is not.
I tested with vector<int>, vector<double> and vector<string>.


Regards,
Saeed
 
E

Erik Wikström

Saeed Amrollahi schrieb:> Dear All
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:
[...]
void f1(std::vector<int> v) [...]
void f2(std::vector<int> v) [...]
void f3(std::vector<int>* pv)

[...]

There is no reference. You have two function that do a call-by-value and
one that does a call-by-reference (via pointer).

Obviously, the first two shouldn't show any measurable performance
difference.


Hi
Sorry for typo and confusion. I actually used reference in the code:
void f1(std::vector<int> v)
void f2(std::vector<int>& v)
void f3(std::vector<int>* pv)

Based on guys' advice, I changed my simple benckmark code to better
one:

template<class T>
void f1(std::vector<T> v)
{
for (int sz = 0; sz < 1000000; sz++)
v.push_back(T());
}

template<class T>
void f2(std::vector<T>& v)
{
for (int sz = 0; sz < 1000000; sz++)
v.push_back(T());
}

template<class T>
void f3(std::vector<T>* pv)
{
for (int sz = 0; sz < 1000000; sz++)
pv->push_back(T());

}

int main()
{

vector<int> v; // empty vector

cout << "f1 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f1(v);
}
cout << "f1 end" << '\n';
v.clear();
cout << "f2 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f2(v);
}
cout << "f2 end" << '\n';
v.clear();
cout << "f3 called" << '\n';
for (int i = 0; i < 10; i++) {
vector<int> v;
f3(&v);
}
cout << "f3 end" << '\n';
v.clear();

return 0;
}

I don't use a precise clock, but I expected a difference order of
magnitude efficiency but it is not.
I tested with vector<int>, vector<double> and vector<string>.

Make sure you measure the right thing:

#include <iostream>
#include <vector>

size_t f1(std::vector<int> v)
{
return v.size();
}

size_t f2(const std::vector<int>& v)
{
return v.size();
}

size_t f3(std::vector<int>* v)
{
return v->size();
}

int main()
{

std::vector<int> v(1000000); // empty vector
std::cout << "Start" << std::endl;

for (int i = 0; i < 1000; ++i)
f1(v);
std::cout << "f1 done" << std::endl;

for (int i = 0; i < 1000; ++i)
f2(v);
std::cout << "f2 done" << std::endl;

for (int i = 0; i < 1000; ++i)
f3(&v);
std::cout << "f3 done" << std::endl;

return 0;
}

This shows the overhead of passing a vector with 10^6 elements by value
instead of by pointer/reference. If you want to be sure you can
rearrange the calls so that f1() is called in second or third and see
what takes the longest.
 
S

Saeed Amrollahi

Saeed Amrollahi schrieb:> Dear All
Hi
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.
In the following code, I don't gain cosiderable performance with call-
by-reference vs. call-by-value. Indeed, the perforamnce is absolutely
unconsiderable:
[...]
void f1(std::vector<int> v)
[...]
void f2(std::vector<int> v)
[...]
void f3(std::vector<int>* pv)
[...]
There is no reference. You have two function that do a call-by-value and
one that does a call-by-reference (via pointer).
Obviously, the first two shouldn't show any measurable performance
difference.
Hi
Sorry for typo and confusion. I actually used reference in the code:
void f1(std::vector<int> v)
void f2(std::vector<int>& v)
void f3(std::vector<int>* pv)
Based on guys' advice, I changed my simple benckmark code to better
one:
template<class T>
void f1(std::vector<T> v)
{
   for (int sz = 0; sz < 1000000; sz++)
           v.push_back(T());
}
template<class T>
void f2(std::vector<T>& v)
{
   for (int sz = 0; sz < 1000000; sz++)
           v.push_back(T());
}
template<class T>
void f3(std::vector<T>* pv)
{
   for (int sz = 0; sz < 1000000; sz++)
           pv->push_back(T());

int main()
{
   vector<int> v; // empty vector
   cout << "f1 called" << '\n';
   for (int i = 0; i < 10; i++) {
           vector<int> v;
           f1(v);
   }
   cout << "f1 end" << '\n';
   v.clear();
   cout << "f2 called" << '\n';
   for (int i = 0; i < 10; i++) {
           vector<int> v;
           f2(v);
   }
   cout << "f2 end" << '\n';
   v.clear();
   cout << "f3 called" << '\n';
   for (int i = 0; i < 10; i++) {
           vector<int> v;
           f3(&v);
   }
   cout << "f3 end" << '\n';
        v.clear();
   return 0;
}
I don't use a precise clock, but I expected a difference order of
magnitude efficiency but it is not.
I tested with vector<int>, vector<double> and vector<string>.

Make sure you measure the right thing:

#include <iostream>
#include <vector>

size_t f1(std::vector<int> v)
{
    return v.size();

}

size_t f2(const std::vector<int>& v)
{
    return v.size();

}

size_t f3(std::vector<int>* v)
{
    return v->size();

}

int main()
{

    std::vector<int> v(1000000); // empty vector
    std::cout << "Start" << std::endl;

    for (int i = 0; i < 1000; ++i)
        f1(v);
    std::cout << "f1 done" << std::endl;

    for (int i = 0; i < 1000; ++i)
        f2(v);
    std::cout << "f2 done" << std::endl;

    for (int i = 0; i < 1000; ++i)
        f3(&v);
    std::cout << "f3 done" << std::endl;

    return 0;

}

This shows the overhead of passing a vector with 10^6 elements by value
instead of by pointer/reference. If you want to be sure you can
rearrange the calls so that f1() is called in second or third and see
what takes the longest.

Hi
I ran your program and I do see the big difference. I really don't
know why my benchmark doesn't work.
I should review my code. Erik, Thomas, Ali, Juha, Soumen and Ron thank
you.
 
K

KalleGuld

        cout << "f1 called" << '\n';
        for (int i = 0; i < 10; i++) {
                vector<int> v;
                f1(v);
        }
        cout << "f1 end" << '\n';
        v.clear();
        cout << "f2 called" << '\n';
        for (int i = 0; i < 10; i++) {
                vector<int> v;
                f2(v);
        }
        cout << "f2 end" << '\n';
        v.clear();
        cout << "f3 called" << '\n';
        for (int i = 0; i < 10; i++) {
                vector<int> v;
                f3(&v);
        }

The problem with your benchmark is that most of the work is done
within the functions themselves.
I have learned when an object is big, I should pass the object using a
reference or pointer to it rather than calling by value.

That's true, but you must understand why. The reason is that when
calling by value, you make a copy of the object, and copying that
object takes time.
But in your example, you just pass an empty vector, and that's quite
quick to copy.
Furthermore, it's only _starting_ the function that suffers when
calling by value, not the work done _inside_ it.

So, to make your benchmark work better, strip the body of your
functions and call your functions more times.
The code below should show the difference quite clearly (part 1 took
about 3 minutes, and part 2 was under a second on my system).


//speedtest.cpp
#include <vector>

#include <iostream>
using namespace std;


double f1(vector<double> in) {
return in[0];
}
double f2(vector<double> &in) {
return in[1];
}
int main() {

vector<double> vec(1000000); //big vector
vec[0]=1.2;
vec[1]=3.4;
double db;
int bigNum = 10000;
cout << "start f1:\n" << endl; //remember to flush...
for (int i=0;i< bigNum ;i++) {
db = f1(vec);
}
cout << "start f2:\n" << endl;
for (int i=0;i< bigNum ;i++) {
db = f2(vec);
}
cout << "end" << endl;

return 0;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top