yet another issue with call by value|reference - c++

The question is simple and may has been discussed before, but I could find a clear answer for my case. Assume I pass a pointer object to a function
#include "foo.h"
int main()
{
foo * aFoo = new foo;
bar(aFoo);
delete aFoo;
aFoo = NULL;
return 0;
}
Then the function is written like this
void bar (foo *f)
{
f->insert();
}
The question:
Is that a call by value or call by reference? I know in call by value, there is an overhead for copying the object from main() to bar(). So I want to be sure that is a call by reference.

It is a call by value, where the value of the pointer aFoo is being copied into the function parameter f.
A call by reference is a call where the parameter is a reference, and side-effects on the argument (and not on objects possibly pointed to by that argument) which occur inside the function are visible to the caller when the function returns.
So for instance this is a function accepting a parameter by reference:
void bar(foo*& f)
// ^
// Here you are taking a pointer by reference
While this is a function accepting a parameter by value:
void bar(foo* f)
// ^
// Here you are taking a pointer to foo by value
You are probably puzzled by the fact that taking a foo by reference and writing:
void bar(foo& f)
{
f.insert();
}
Has pretty much the same effect as passing a pointer to the same foo object by value and writing:
void bar(foo* f)
{ // Precondition: f != nullptr
f->insert();
}
However, the two things are conceptually different. While the value/state of the object you passed in the first case can be different when the function returns from the value/state it had before calling the function, in the second case the value of the pointer you provided will be the same as it was before you called bar() - while the object pointed to may have undergone some state change.
Also notice, that a pointer can be null, while a reference is always bound to an object.

In your case, it is call by value in terms of the pointer to Foo formally. But since you pass a pointer to a function instead of the class instance itself, then it is conceptually call by reference in terms of the class instance since the function call does not copy the whole instance but just its pointer.
Foo fooInstance;
// providing a way to point (less formally you can call it refer) to the instance
Foo* fooPointer = &fooInstance;
// this function call is call by value (passing the value of the pointer).
// but you can logically view it as 'call by reference' to fooInstance.
bar(fooPointer);

Related

Is there a more concise way to pass function result as shown here

I'd like to call my function that creates the object to be passed to a method on the same line, but if I do I get an initial value of reference to non-const must be an lvalue compile-time error. To get it to compile I need to declare a temporary holder variable and set it equal to the factory method resul.
I realize this is because the reference is simply an address of a storage location, but is C++ really not able to recognize the construct and create a temporary holder variable? I am not a great C++ coder, so I assume I am missing something or that there is a gap in my knowledge, or both - and I hope you can help. I am using GCC, and C++ 11, with VS Code as my editor.
class Bar {};
class Foo {
const Baz add(Bar& bar) { /* .... */ }
};
void doIt() {
Baz baz;
// what compiles...
Bar bar = createBar();
baz.add(bar);
// What I'd like... but it gives me "initial value of reference to non-const must be an lvalue"
// baz.add(createBar());
}
Change the signature to:
Baz add(Bar bar) { /* .... */ }
Since you need to retain the value (to put it in a vector) you must have ownership of the object. You've declared that you take a reference to avoid making a copy, but you do make a copy -- when you put it in the vector!
Instead, take the object by value, and then the caller can move-construct the argument, and add() can move-construct the vector element. (C++17 further guarantees move-elision in some of these cases, so the object could be directly constructed in the vector.)
There is no point in returning the Baz object as const since it's not yours anymore; the caller can decide if they want to receive it as const.
Your doIt() becomes:
void doIt() {
// Argument is move-constructed from the temporary.
baz.add(createBar());
}
In your method:
Baz Foo::add(Bar bar) {
// Perform your checks, then...
the_vector.emplace_back(std::move(bar));
return some_baz;
}
The general advice is that if your function needs to take ownership of an object, it should receive it by value. This allows the caller to decide what they want to do: make a copy because they still need the original, or move the original into the argument and let the callee steal the state.

Distinguish between temporaries and non-temporaries in function signature?

I want to create a class Bar that can distinguish between temporaries and non-const non-temporaries. According to this (about 25% down the page), I can get away with this if the second StealPointer takes a const reference (to a pointer in my case), but in my code it just uses the StealPointer(Foo*&& foo) version regardless of how it is called.
class Foo {};
class Bar {
public:
// For when StealPointer(new Foo()); is called. Bar instance then owns the
// pointer.
void StealPointer(Foo*&& foo) {} // Get the temporaries only.
// For when a Foo* already exists and is passed in StealPointer(my_foo_ptr);
// Takes ownership and invalidates the pointer that the caller once had.
void StealPointer(Foo*&) {} // Get lvalues only.
};
Can I do this? Is there a way to do this that only requires one function? If it matters, Bar is going to store the pointer in a unique_ptr and I would like to avoid the additional syntax of passing in a unique_ptr or making the caller do something with std::move. I can't just pass the pointers by reference, because temporaries of type Foo* can't be converted to Foo*&.
Make your function templated and let std::unique_ptr worry about those details for you.
template <typename Ptr>
void StealPointer(Ptr&& p) // a universal reference, matches *any* type of value
{
uniqptr = std::move(p); // Works for both rvalues and lvalues
}

How the Reference itself is passed [duplicate]

I would like to clarify the differences between by value and by reference.
I drew a picture:
So, for passing by value, a copy of an identical object is created with a different reference, and the local variable is assigned the new reference, so to point to the new copy
How should I understand the following?
If the function modifies that value, the modifications appear also
within the scope of the calling function for both passing by value and by reference
I think much confusion is generated by not communicating what is meant by passed by reference. When some people say pass by reference they usually mean not the argument itself, but rather the object being referenced. Some other say that pass by reference means that the object can't be changed in the callee. Example:
struct Object {
int i;
};
void sample(Object* o) { // 1
o->i++;
}
void sample(Object const& o) { // 2
// nothing useful here :)
}
void sample(Object & o) { // 3
o.i++;
}
void sample1(Object o) { // 4
o.i++;
}
int main() {
Object obj = { 10 };
Object const obj_c = { 10 };
sample(&obj); // calls 1
sample(obj) // calls 3
sample(obj_c); // calls 2
sample1(obj); // calls 4
}
Some people would claim that 1 and 3 are pass by reference, while 2 would be pass by value. Another group of people say all but the last is pass by reference, because the object itself is not copied.
I would like to draw a definition of that here what i claim to be pass by reference. A general overview over it can be found here: Difference between pass by reference and pass by value. The first and last are pass by value, and the middle two are pass by reference:
sample(&obj);
// yields a `Object*`. Passes a *pointer* to the object by value.
// The caller can change the pointer (the parameter), but that
// won't change the temporary pointer created on the call side (the argument).
sample(obj)
// passes the object by *reference*. It denotes the object itself. The callee
// has got a reference parameter.
sample(obj_c);
// also passes *by reference*. the reference parameter references the
// same object like the argument expression.
sample1(obj);
// pass by value. The parameter object denotes a different object than the
// one passed in.
I vote for the following definition:
An argument (1.3.1) is passed by reference if and only if the corresponding parameter of the function that's called has reference type and the reference parameter binds directly to the argument expression (8.5.3/4). In all other cases, we have to do with pass by value.
That means that the following is pass by value:
void f1(Object const& o);
f1(Object()); // 1
void f2(int const& i);
f2(42); // 2
void f3(Object o);
f3(Object()); // 3
Object o1; f3(o1); // 4
void f4(Object *o);
Object o1; f4(&o1); // 5
1 is pass by value, because it's not directly bound. The implementation may copy the temporary and then bind that temporary to the reference. 2 is pass by value, because the implementation initializes a temporary of the literal and then binds to the reference. 3 is pass by value, because the parameter has not reference type. 4 is pass by value for the same reason. 5 is pass by value because the parameter has not got reference type. The following cases are pass by reference (by the rules of 8.5.3/4 and others):
void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1
void f2(Object const& op);
Object b; f2(b); // 2
struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference
When passing by value:
void func(Object o);
and then calling
func(a);
you will construct an Object on the stack, and within the implementation of func it will be referenced by o. This might still be a shallow copy (the internals of a and o might point to the same data), so a might be changed. However if o is a deep copy of a, then a will not change.
When passing by reference:
void func2(Object& o);
and then calling
func2(a);
you will only be giving a new way to reference a. "a" and "o" are two names for the same object. Changing o inside func2 will make those changes visible to the caller, who knows the object by the name "a".
I'm not sure if I understand your question correctly. It is a bit unclear. However, what might be confusing you is the following:
When passing by reference, a reference to the same object is passed to the function being called. Any changes to the object will be reflected in the original object and hence the caller will see it.
When passing by value, the copy constructor will be called. The default copy constructor will only do a shallow copy, hence, if the called function modifies an integer in the object, this will not be seen by the calling function, but if the function changes a data structure pointed to by a pointer within the object, then this will be seen by the caller due to the shallow copy.
I might have mis-understood your question, but I thought I would give it a stab anyway.
As I parse it, those words are wrong. It should read "If the function modifies that value, the modifications appear also within the scope of the calling function when passing by reference, but not when passing by value."
My understanding of the words "If the function modifies that value, the modifications appear also within the scope of the calling function for both passing by value and by reference" is that they are an error.
Modifications made in a called function are not in scope of the calling function when passing by value.
Either you have mistyped the quoted words or they have been extracted out of whatever context made what appears to be wrong, right.
Could you please ensure you have correctly quoted your source and if there are no errors there give more of the text surrounding that statement in the source material.

transferring parameters in C++

can I have this snippet of the code:
C *pa1 = new C(c2);
and I transfer it to another function:
foo(pa1);
what exactly do I transfer actual pointer or its copy, thanks in advance
and can somebody give some info about in which cases info is copied, and in which I transfer actual pointer
declaration of foo:
foo(A const *pa)
Assuming foo is declared as:
void foo(C* p);
you are passing a copy of the pointer.
This means, if foo does this:
p = &some_other_object;
that change to the pointer won't be seen by the caller.
It also means we're copying the pointer, not the thing pointed to. If foo does this:
p->bar = "Smurf!"
pa1 in the caller will also see the change. For this reason, pointers are often used to implement a kind of pass-by-reference.
If foo were declared:
void foo(C*& p);
then p would be a reference to pa1, and changes to p would result in changes to pa1. Historically, this has also been implemented using pointers to pointers:
void foo(C** p);
in which case you call foo like this:
foo(&pa1);
and foo can do something like:
*p = &some_other_object;
to change what pa1 points to.
Since pa1 is of type pointer-to-C, you are passing a pointer to C to the function foo. You are not copying the actual object.
To pass an object, you would need foo to take an object of type C and to dereference pa1 when passing it:
void foo(C);
...
foo(*pa1);
Since pa1 is a pointer (as you have defined it as a C *), you are passing a pointer to the C object into foo.
That said, whether you are passing the pointer by value or by reference is unknown without seeing the declaration of foo.
C *pa1;
object of type 'C*' is created on the stack (local variable pa1)
pa1 = new C(c2);
object of type 'C' is created on the heap, its address is returned into 'pa1' variable
foo(pa1)
We can say "object of type 'C*' (variable pa1) is passed by-value to function foo, the function gets a copy of the pointer",
But also "object of type 'C' (this one created on the heap) passed by-reference (through pointer) to function foo, no copy 'C' object is made.
To pass by-reference (without making a copy of an object) either c++ reference to the object can be used or pointer to the object. They act similar when going about function parameter passing, i.e all of 4 lines below gives the same effect, passing by-reference (these are const references, remove const keyword to be able to permanently modify the object by the foo function):
foo(const A *pa) { pa->DoSth(); } /*...*/ foo(some_pointer);
foo(const A *pa) { pa->DoSth(); } /*...*/ foo(&some_reference);
foo(const A &pa) { pa.DoSth(); } /*...*/ foo(*some_pointer);
foo(const A &pa) { pa.DoSth(); } /*...*/ foo(some_reference);

Pass by reference and value in C++

I would like to clarify the differences between by value and by reference.
I drew a picture:
So, for passing by value, a copy of an identical object is created with a different reference, and the local variable is assigned the new reference, so to point to the new copy
How should I understand the following?
If the function modifies that value, the modifications appear also
within the scope of the calling function for both passing by value and by reference
I think much confusion is generated by not communicating what is meant by passed by reference. When some people say pass by reference they usually mean not the argument itself, but rather the object being referenced. Some other say that pass by reference means that the object can't be changed in the callee. Example:
struct Object {
int i;
};
void sample(Object* o) { // 1
o->i++;
}
void sample(Object const& o) { // 2
// nothing useful here :)
}
void sample(Object & o) { // 3
o.i++;
}
void sample1(Object o) { // 4
o.i++;
}
int main() {
Object obj = { 10 };
Object const obj_c = { 10 };
sample(&obj); // calls 1
sample(obj) // calls 3
sample(obj_c); // calls 2
sample1(obj); // calls 4
}
Some people would claim that 1 and 3 are pass by reference, while 2 would be pass by value. Another group of people say all but the last is pass by reference, because the object itself is not copied.
I would like to draw a definition of that here what i claim to be pass by reference. A general overview over it can be found here: Difference between pass by reference and pass by value. The first and last are pass by value, and the middle two are pass by reference:
sample(&obj);
// yields a `Object*`. Passes a *pointer* to the object by value.
// The caller can change the pointer (the parameter), but that
// won't change the temporary pointer created on the call side (the argument).
sample(obj)
// passes the object by *reference*. It denotes the object itself. The callee
// has got a reference parameter.
sample(obj_c);
// also passes *by reference*. the reference parameter references the
// same object like the argument expression.
sample1(obj);
// pass by value. The parameter object denotes a different object than the
// one passed in.
I vote for the following definition:
An argument (1.3.1) is passed by reference if and only if the corresponding parameter of the function that's called has reference type and the reference parameter binds directly to the argument expression (8.5.3/4). In all other cases, we have to do with pass by value.
That means that the following is pass by value:
void f1(Object const& o);
f1(Object()); // 1
void f2(int const& i);
f2(42); // 2
void f3(Object o);
f3(Object()); // 3
Object o1; f3(o1); // 4
void f4(Object *o);
Object o1; f4(&o1); // 5
1 is pass by value, because it's not directly bound. The implementation may copy the temporary and then bind that temporary to the reference. 2 is pass by value, because the implementation initializes a temporary of the literal and then binds to the reference. 3 is pass by value, because the parameter has not reference type. 4 is pass by value for the same reason. 5 is pass by value because the parameter has not got reference type. The following cases are pass by reference (by the rules of 8.5.3/4 and others):
void f1(Object *& op);
Object a; Object *op1 = &a; f1(op1); // 1
void f2(Object const& op);
Object b; f2(b); // 2
struct A { };
struct B { operator A&() { static A a; return a; } };
void f3(A &);
B b; f3(b); // passes the static a by reference
When passing by value:
void func(Object o);
and then calling
func(a);
you will construct an Object on the stack, and within the implementation of func it will be referenced by o. This might still be a shallow copy (the internals of a and o might point to the same data), so a might be changed. However if o is a deep copy of a, then a will not change.
When passing by reference:
void func2(Object& o);
and then calling
func2(a);
you will only be giving a new way to reference a. "a" and "o" are two names for the same object. Changing o inside func2 will make those changes visible to the caller, who knows the object by the name "a".
I'm not sure if I understand your question correctly. It is a bit unclear. However, what might be confusing you is the following:
When passing by reference, a reference to the same object is passed to the function being called. Any changes to the object will be reflected in the original object and hence the caller will see it.
When passing by value, the copy constructor will be called. The default copy constructor will only do a shallow copy, hence, if the called function modifies an integer in the object, this will not be seen by the calling function, but if the function changes a data structure pointed to by a pointer within the object, then this will be seen by the caller due to the shallow copy.
I might have mis-understood your question, but I thought I would give it a stab anyway.
As I parse it, those words are wrong. It should read "If the function modifies that value, the modifications appear also within the scope of the calling function when passing by reference, but not when passing by value."
My understanding of the words "If the function modifies that value, the modifications appear also within the scope of the calling function for both passing by value and by reference" is that they are an error.
Modifications made in a called function are not in scope of the calling function when passing by value.
Either you have mistyped the quoted words or they have been extracted out of whatever context made what appears to be wrong, right.
Could you please ensure you have correctly quoted your source and if there are no errors there give more of the text surrounding that statement in the source material.