开发者

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


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.


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"


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.


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.


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.


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.


  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.


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.


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.


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


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜