Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 902
Michael Sync Avatar asked Jun 26 '10 15:06

Michael Sync


2 Answers

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 :)

like image 150
Matthieu M. Avatar answered Oct 06 '22 21:10

Matthieu M.


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.

like image 33
Konrad Rudolph Avatar answered Oct 06 '22 20:10

Konrad Rudolph