views:

426

answers:

12
+5  Q: 

Confusion in C++

I'm very new to C++ and I'm currently learning it. I got a few questions..

  1. What is the differences between void DoSomething(const Foo& foo) and void DoSomething(Foo foo)? If we don't specify & then the instance of Foo will be passed by value ( not reference ). It will be the same as having const + & in argument except no checking at compile-time. So, Why does having const + & become the best practice over the argument without & and const?

    In C#, passing the object is "by reference" but seems like it's not in C++.

  2. The book that I'm reading said that Member functions pass the implicit parameter by reference..

    Could anyone give me the sample of implicit parameter and by reference? I know that if we want to pass the object by reference, we need to use & (e.g. Foo(Person& p) ) but how come C++ pass the object by reference for implicit parameter? I read that implicit parameter in C++ is like Contructor(string str) : strMemberVariable(str) {} ...

  3. Is the array the only that pass by reference in C++?

  4. Why can't I use Foo fInstance in Foo class?

Example:

class Foo {

public:    
    Foo() { }

    Foo(const Foo& f) : fInstance(f) {   }  

    Foo fInstance;      
};

Thanks in advance.

+1  A: 

The difference between void DoSomething(const Foo& foo) and void DoSomething(Foo foo) is the first passes the parameter by reference and the second by value. The practical differences are:

  1. Efficiency. Passing by value may require the copy constructor to be called. If the copy constructor is expensive, passing by value will add more overhead.
  2. Applicability. Passing by value requires a public copy constructor. If a class does not support a copy constructor, it cannot be passed by value.
  3. Semantics. When passing by reference, you don't know who the object may be referenced. If the underlying object is changed for some other reason, the value of the reference will change.

To explain #3 a bit better, consider this situation:

std::string global_string;

void foo(const std::string &str)
{
    if (str.empty())
    {
        global_string = "whatever";
        // is str still empty??
    }
}

If foo is called as foo(global_string), then when you change global_string this also changesstr.

R Samuel Klatchko
Michael Sync
@MichaelSync - passing by const reference is better because it is more efficient and will work even if the type cannot be copied (i.e. my #1 and #2). `const` says the function will not modify the object, but does not cover the case of it being modified through some other method.
R Samuel Klatchko
Thanks. I added one more question in my post. Could you please answer this as well? Thanks.
Michael Sync
But in your very example, the function might change `str` because of aliasing with `global_string` :)
FredOverflow
jalf
I would add that passing by reference allow to pass objects of a derived type... that's quite useful!
Matthieu M.
@Mat: Passing by value also allows passing objects of derived type, it's just that the semantics you get (object slicing) is probably not what you want ;)
FredOverflow
+1  A: 

One at a time:

  1. doStuff(Foo f) means a new Foo object will be created on the stack when the method is called - AKA by-value. Calling doStuff(const Foo &f) means you are just passing a new reference , object is not duplicated, you only hold a reference to it. This is the safest way of passing arguments since it does not involve duplicating a copy of an object. This is called passing by-reference and is the closest you will get to Java/C# behavior.

  2. Which implicit parameter are you talking about?

  3. Again, arrays (assuming they are std::arrays) can be passed by value, pointer, or reference - there is no single behavior. As Konard mentioned, C-style arrays (nothing more than blocks of memory) cannot be passed by value.

Yuval A
Michael Sync
It doesn't mean the object can't be modified, it means the reference can't be modified.
Yuval A
Okay. Thanks. Yuval..
Michael Sync
FredOverflow
I think the point is that passing by reference saves memory.
Javier Badia
Arrays **cannot** be passed by value in C++.
Konrad Rudolph
@Konrad: C-style arrays can't, but `std::array` can ;)
FredOverflow
@Fred: so can `std::vector` – it’s just any other class. ;-) But I think what is *meant* here is the good old C-style array.
Konrad Rudolph
@Konrad: Absolutely, hence my smiley ;)
FredOverflow
A: 
void DoSomething(Foo foo)

Actually passes a copy of foo, and

void DoSomething(Foo& foo)

Passes a reference to foo, so if you modify foo in your function, you'll modify the original foo. I hope this makes sense.

As for arrays, an array is actually a pointer to the beginning of an array, and that pointer is passed around (the whole array is not copied).

array[5] = 0;//is the same as :
*(array+5) = 0; //this
fingerprint211b
The last two lines in your answer are incorrect. You are assuming `sizeof(array[0])==1`
Yuval A
Not really, the pointer has a type, and will be incremented by sizeof(that_type). (If I understood correctly what you meant to say)
fingerprint211b
@YuvalA - you are incorrect. `arr[x]` and `*(arr + x)` are semantically equivalent in C++. Pointer arithmetic takes into account the type of the pointer and does the right thing.
R Samuel Klatchko
There is absolutely no way to pass references by value in C++.
FredOverflow
Michael Sync
@FredOverflow : What I mean is that the reference itself is copied...
fingerprint211b
You can't copy references in C++ because they aren't objects. References were specifically introduced into C++ to support pass by reference.
FredOverflow
You're right, my mistake. Fixed.
fingerprint211b
"Passes a constant reference to foo, so if you modify foo in your function" -> But you **cannot** modify `foo`! It's not the reference that you explicitly mark `const`, but the view on the object. References are **always** implicitly constant. There is no such thing as a mutable reference in C++.
FredOverflow
Right, I meant that as a general case for references/pointers, not const references. Fixed, again.
fingerprint211b
+4  A: 

In C#, passing the object is "by reference" but seems like it's not in C++.

No, this is wrong, it’s a common misconception. In languages like C#, VB and Java, variables are always passed by value (exception explicitly passed as ref in C# or ByRef in VB).

The difference to C++ is that variables don’t contain a class’ object itself, they only contain the reference. So what is passed to the method is not the object itself, only its reference (but that is passed by value).

The difference is rather important. If C# used pass by reference, the following code would print a different result:

void foo(string s) {
    s = "world";
}

string s = "hello";
foo(s);
Console.WriteLine(s); // prints "hello"
Konrad Rudolph
>> explicitly passed as ref in C# or ByRef in VB)I don't think so. In C#, by-reference is default when you are passing the object...
Michael Sync
Sorry.. I should have mentioned that passing the object in C# is by ref (not string or int or etc).
Michael Sync
@Michael: "In C#, by-reference is default when you are passing the object" -> No, it's just that the reference is passed by value. This is different from pass by reference which you can achieve with the `ref` keyword in C#.
FredOverflow
@Michael: `string` is a normal class in C#, nothing special at all. You can test this example with any other class instead of `string` and get the same behaviour.
Konrad Rudolph
A: 

What is the differences between void DoSomething(const Foo& foo) and void DoSomething(Foo foo)

DoSomething(Foo foo) passes the object foo by value if Foo is a primitive data-type, but by reference if Foo is a user defined data-type. But in the second case, if you change foo, it gets reflected back to the original object, which is often undesirable. This is taken care of by DoSomething(const Foo& foo) which passes foo by reference (thus saving the extra memory cost of passing by value) and still does not give write access on foo to the DoSomething function. Thus, it is a best practice.

Could anyone give me the sample of implicit parameter and by reference?

An example of implicit parameter in member functions is the reference to the parent object, ie. this which is never mentioned in the function's definition, but always available for use.

Is the array the only that pass by reference in C++?

No, all user defined objects are passed by reference.

Prashant
okay. this -> membervariable means "implicit parameter", isn't it? I'm clear now. Thanks.
Michael Sync
"all user defined objects are passed by reference" -> Completely wrong. Are you confusing C++ with C# or Java?
FredOverflow
Basically, everything in this answer is wrong.
Konrad Rudolph
+4  A: 

Why can't I use Foo fInstance in Foo class?

Because conceptually, an object of Foo would need an infinite amount of space. Technically, the type Foo is incomplete in the definition of Foo.

What you probably want is a pointer to Foo as a member.

FredOverflow
A: 

The book that I'm reading said that Member functions pass the implicit parameter by reference..

The book is talking about the implicit pointer this that is passed to every non-static member function defined in a class. That because C++ holds a copy of each member function in the class not in every object so the method should know about what object of that class it should work on.

class FOO{
 int x;
 void doSomthing(int x);
}

void FOO::doSomething(int x){
  x = x;
}

would be compiled into something like that

void FOO::doSomething(FOO* this, int x){
  this->x = x;
}

Since static functions are class functions rather than object functions, they don't need an object to be created in order to be called, so they shouldn't have access to non-static fields of the class and thus doesn't need a this pointer to the object.

LmSNe
`this->`, and your example seems incorrect, it should compile to `this->x = this->x` which is quite useless. This trick only work in the initializer list.
Matthieu M.
@Mathieu: no, `x` refers to the local variable (the parameter – inner scope hides outer scope) while `this->x` refers to the member.
Konrad Rudolph
@Matthieu: what Konard said is what I meant. But You are right about the ->operator rather than the . operator. my mistake :)
LmSNe
A: 

It's not quite accepted "good practice" to pass by const reference instead of by value.

This blog post explains why.

People tend to think that const reference is faster, but the truth is that the compiler is allowed to optimize away the copy when passing by value, so passing by value is a good default (and indeed, the standard library typically does this. For example, std::for_each takes two iterators by value and one functor by value)

The main reason to use const reference is if the object cannot logically be copied. Say the object represents a window. You don't want a second window to appear on screen just because you passed the window object to another function, implicitly creating a copy.

Many objects represents something that cannot or should not be copied. Those will typically have a private copy constructor, and will have to be passed by reference or const reference to functions.

Another reason to pass by reference (const or otherwise) might be to use polymorphic objects. Say you have a base class B and a derived class D. You can pass an object of type D as a const B& safely, but passing it by value as an object of type B risks introducing slicing (only the B subobject is copied, instead of the entire D object).

So a good practice is to pass by value by default, but passing by const reference certainly also has its place. Both are in the language for a reason.

jalf
@jalf: color me sceptical. The standard library only passes iterators and function objects by value, operating under the assumption that these objects are typically small. **If** compilers can indeed optimize away pass by value, then this is certainly only true in recent compilers, and even then only in special circumstances. I’m not at all convinced that even modern compilers elide copies for arguments (as opposed to return values). The blog post you refer to doesn’t back you up, either: it only talks about NRVO (i.e. return values) and pass-by-value in places where a copy is intended anyway.
Konrad Rudolph
Last but not least, if what you said were true, rvalue references would be virtually redundant. In reality, they were introduced into the language to address precisely these shortcomings.
Konrad Rudolph
@jalf: I disagree. Iterators are special, they are *designed* to be passed by value, as are function objects. If you take a look at Effective C++, the book suggests to pass primitives, iterators and functors by value and almost everything else by reference-to-const. The article you linked only applies to C++0x. Without move semantics, passing everything by value is a bad advice, imho.
FredOverflow
@Konrad: modern compilers are very good at copy elision. True, it's less reliable in old compilers, but today, it's a pretty safe bet. And the blog post points out that pass-by-value may be *faster* in cases where the copy is intended anyway, but also that it is generally *no slower* in any case.Of course there's no guarantee that every copy will be elided, but it is impressively often the case, if you look at the compiler output. :) Feel free to prove me wrong though. Try it out, and check the disassembly.
jalf
@Konrad: No, rvalue refs were introduced for a few other reasons as well. Perfect forwarding is one example. Move semantics also can't be implemented completely and robustly without rvalue refs. Copy elision only gets you some of the way (and is reliant on the compiler to optimize)
jalf
@jalf: you **don’t need** move semantics when you can elide copies. All you need is `swap`.
Konrad Rudolph
+10  A: 

1 What is the differences between void DoSomething(const Foo& foo) and void DoSomething(Foo foo)? If we don't specify & then the instance of Foo will be passed by value ( not reference ). It will be the same as having const + & in argument except no checking at compile-time. So, Why does having const + & become the best practice over the argument without & and const?

In C#, passing the object is "by reference" but seems like it's not in C++.

There are several differences, in order of importance:

  • If the object Foo cannot be copied, you need to pass it by reference
  • If the object Foo is a base class, you should get it by reference so that users can call your functions with derived classes
  • The value of the actual object might change even though you hold a const reference to it
  • Efficiency, copying user types might be expensive, but compilers may be smart enough to figure it out so...

2 The book that I'm reading said that Member functions pass the implicit parameter by reference..

Could anyone give me the sample of implicit parameter and by reference? I know that if we want to pass the object by reference, we need to use & (e.g. Foo(Person& p) ) but how come C++ pass the object by reference for implicit parameter? I read that implicit parameter in C++ is like Contructor(string str) : strMemberVariable(str) {} ...

By implicit parameter you should understand this, that is the object itself. It is effectively passed by reference since you can modify its state in the member function.

Following Konrad's remark: note that this itself is not passed by reference, this is a reference (pointer) to the object, but is passed by value. You can't change the memory address of your object as you wish ;)

3 Is the array the only that pass by reference in C++?

They aren't. You will see changes to the elements of the array, but the array (structure) will not change.

Following FredOverflow's remark, an illustration:

void fun(int* p, size_t size);

int main(int argc, char* argv[])
{
  int array[15];
  fun(array, 15);
}

We don't know what fun does, it will probably change some elements of array, but whatever its action, array will remain an Array of 15 integers: the content changes, the structure does not.

As a result, to change array we need another declaration:

void changer(int*& array, size_t& size);

This way we can change both the content and the structure (and pass back the new size too). And of course we can only call this function with an array that was dynamically allocated.

4 Why can't I use Foo fInstance in Foo class?

Because that's infinite recursion. Think about it from a compiler point of view, and try to guess the size of Foo. The size of Foo is the sum of the sizes of its attributes, plus possibly some padding and type information. Also, an object size is at least 1 so that it can be addressed. So, if Foo has a Foo, what's its size :) ?

The usual solution is to use a smart pointer:

class Foo
{
public:

private:
  std::unique_ptr<Foo> mInstance;
};

Because the size of a pointer does not depend on the size of the object pointed to, so there is not recursion going on here :)

Matthieu M.
"You will see changes to the elements of the array, but the array (structure) will not change." -> I don't understand what you mean by that, please elaborate.
FredOverflow
Very good answer. The only problem I have concerns the `this` pointer: is it really passed by reference? I don’t think so – I think it’s passed by value. Certainly, *changing* it is illegal, even using `const_cast`, and the compiler treads it as an rvalue.
Konrad Rudolph
@Konrad: It does not even make sense to talk about changing `this` via `const_cast` because `this` isn't `const` to begin with :) `this` is a pointer, pointers are scalar types, and scalar types don't have constant rvalues.
FredOverflow
@Konrad: passing a pointer to an object is a way to pass the object by reference.
bk1e
@bk1e: You *could* say that `*this` is passed "by reference", but `this` (without the dereference operator) definitely isn't passed by reference.
FredOverflow
@Fred: well, `this` could conceivably be declared as `class_type* const` (perfectly reasonable declaration, and in fact many good books on C++ encourage the reader to think of `this` as declared that way) in which case a `const_cast` *would* help.
Konrad Rudolph
@bk1e: Yes of course, but “reference” has a very distinct, fixed meaning in C++ and pointers and references are *not* the same thing, and neither is passing a pointer (by value) and pass by reference.
Konrad Rudolph
@Konrad: The standard disagrees with you. Section 9.3.2 clearly defines `this` as a prvalue, and there is no such thing as a const prvalue, so there is no constness to cast away. By your logic, it should also be possible to cast the constness away from the null pointer.
FredOverflow
@Fred: Hmm, what’s a prvalue? I couldn’t find a reference to it. But §9.3.2 says that `this` has type `T*` in a non-const member function and is a non-lvalue (and hence an rvalue, since §3.10 says that “every expression is either an lvalue or an rvalue”) so that’s that. ;-)
Konrad Rudolph
@Konrad: Sorry, I was quoting from the C++0x FCD. A C++0x prvalue is a C++98 rvalue.
FredOverflow
@Konrad, @Fred: I have updated my answer following your remarks, thanks. I won't enter the debate on the status of `this` however, I have never been much of a standardista.
Matthieu M.
@Matthieu M.: I think you meant `fun(array, 15);`?
Lazer
@Lazer: yes of course, thanks for catching that :)
Matthieu M.
Array in C++ is passed by reference by default.. void funct(int x[], int x_size){for(int i = 0; i<x_size; i++){x[i] += 1;}}int main(){int n[5] = {1,2,3,4,5};int n_size = 5;funct(n, n_size);for(int i = 0; i<n_size; i++){cout << n[i];}return 0;}
Michael Sync
Or Am I in wrong direction?
Michael Sync
No, it's not, the type degenerates to a pointer, and its elements are thus accessible by reference but not the array itself.
Matthieu M.
A: 
  What is the differences between void DoSomething(const Foo& foo) and

void DoSomething(Foo foo)?

pragmatically there is no difference, the const will prevent you from changing the contents of 'foo' whereas passing by value will also not affect the contents of the argument, however in terms of effectiveness the const Foo& foo is more effective since it wouldn't create a copy when the object is passed to the method.

Anders K.
+7  A: 

Since there are so many misconceptions and downright false answers here, this is my attempt at redressing this:

What is the differences between void DoSomething(const Foo& foo) and void DoSomething(Foo foo)?

As others have said, the second code requires a copy (usually calling the copy constructor of Foo).

So, Why does having const + & become the best practice over the argument without & and const?

There are a few special purporses that others have already answered (e.g. runtime polymorphism). This doesn’t explain why it has become best practice. The reason for this is simple and ugly: because it is magnitudes more efficient. Imagine passing a vector or string to another method – or basically just any big data structure. The cost of copying this will generally be huge, and methods may be called often in code – in fact, methods are usually called very often, otherwise the code is badly designed.

On the other hand, when you pass the object as a const reference then this is internally (usually) implemented via a pointer. Pointers can always be copied efficiently, on all architectures.

The book that I'm reading said that Member functions pass the implicit parameter by reference..

I think the book is wrong. Member functions of classes implicitly get passed a this pointer that refers to the current object. However, this is a pointer, and C++ forbids changing it. There is no reason why it would be passed by reference.

Is the array the only that pass by reference in C++?

Arrays are rarely passed at all in C++ – they are usually passed as pointers:

void foo(int[] x) { … }

is actually the same as

void foo(int* x) { … }

The compiler treats these two declarations identical. When you try calling either of these methods and pass it an array x, C++ will implicitly convert the array to a pointer to its first element – this is called “decay”. So, foo(x) will become foo(&x[0]).

However, arrays can instead be passed by reference if their size is given:

void foo(int (&x)[4]);

But once again, you are explicitly declaring that the array be passed by reference.

Konrad Rudolph
FredOverflow
@Fred: thanks for correcting me. See updated answer.
Konrad Rudolph
I like your answer now :) +1 from me.
FredOverflow
great.. thanks a lot for answer.. i now have clear understanding ... thanks a lot..
Michael Sync
A: 

What is the differences between void DoSomething(const Foo& foo) and void DoSomething(Foo foo)?

Broadly speaking, the latter will deep copy the argument being passed (in other words, it makes a copy of the original Foo object). The former will make a shallow copy of the argument being passed (copying its address to an immutable const reference rather than copying the actual Foo object).

Both of these versions have access to the members of the Foo object being passed. Neither of them will modify the Foo object in the caller. The basic difference, provided that the function does not need a deep copy, is that the former is more efficient because it avoids the need to deep copy.

Could anyone give me the sample of implicit parameter and by reference? I know that if we want to pass the object by reference, we need to use & (e.g. Foo(Person& p) ) but how come C++ pass the object by reference for implicit parameter? I read that implicit parameter in C++ is like Contructor(string str) : strMemberVariable(str) {} ...

In the context of parameterized, unary constructors (constructors taking one argument), they can be implicit (default) or explicit.

class Foo
{
    Foo(int x) {...}
};

This is implicit. It allows us to write code like:

Foo foo = 123;

void f(const Foo& x);
f(123);

While this is explicit:

class Foo
{
    explicit Foo(int x) {...}
};

... and would not the previous code. The previous code would have to be modified accordingly:

Foo foo(123);

void f(const Foo& x);
f(Foo(123) );

It is generally a good habit to make such constructors explicit, with the exception of the copy constructor which I won't go into here as that gets rather involved.

Is the array the only that pass by reference in C++?

I am not exactly sure what is being asked here, but arrays cannot be passed by value if that's what you mean. We can only pass around references/pointers to arrays:

// takes an array of 10 integers
void fn(int(&some_array)[10]);

// takes a pointer to an int array
void fn(int* some_array);

// takes a pointer to an int array (the 10 
// literal constant is ignored) and this function
// can likewise take any pointer to int
void fn(int some_array[10]);

Why can't I use Foo fInstance in Foo class?

That's infinitely recursive. Foo stores fInstance, fInstance stores another fInstance, and so on. There's nothing to stop the recursion so you'd just have objects storing objects storing objects storing objects and so on until you run out of memory. Thus compilers detect that condition and disallow since no legitimate runtime behavior can come of it. There would also be no way to determine the size of Foo - that would be an infinite value.