Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ pass-by-value with non-primitive types?

I must have a fundamental misunderstanding about C++11. My professors told me it wasn't possible to pass a non-primitive type to a function except by reference or pointer. However, the following code works just fine

#include <iostream>
using namespace std;

class MyClass
{
public: 
    int field1;
};

void print_string(string s) { 
    cout << s << endl; 
}

void print_myclass(MyClass c) { 
    cout << c.field1 << endl; 
}

int main(int argc, char *argv[]) 
{
    string mystr("this is my string"); 
    print_string(mystr); // works
    MyClass m; 
    m.field1=9; 
    print_myclass(m); 
    return 0;
}

Running the program yields the following output

this is my string
9

RUN SUCCESSFUL (total time: 67ms)

I'm using MinGW/g++ on Win7

Why does that work? I thought non-primitive types couldn't be passed by value?!

like image 749
Jared Lindsey Avatar asked Aug 21 '13 00:08

Jared Lindsey


1 Answers

Non-primitive types can certainly be passed by value. (This is covered in section 5.2.2 [expr.call] of the C++ Standard.)

However, there are a few reasons why this is often discouraged, especially in C++03 code.

First, for large objects, it is less efficient to do so (when compared with passing by reference), as the data is passed on the stack. A reference will take one word on the stack, so passing any object via the stack which is larger than one word will necessarily be slower.

Second, passing by value invokes the copy constructor (or, as @templatetypedef points out, potentially the move constructor in C++11). This additional processing could incur a certain amount of overhead.

Third, you may have intended to modify the passed in object, but by passing in a copy (by value), any changes you make within the function will not affect the original object. So it is important to get the semantics correct (ie. whether or not you want to modify the original). Hence this is a potential bug in some circumstances.

Finally, if there is a poorly written class with no copy constructor or assignment operator, the compiler will automatically generate a default one for you. This will perform a shallow copy, which could cause problems such as memory leaks. This is yet another good reason why it is very important to implement these special methods. Full details are in this article:

  • The Rule of Three in C++

In general for C++03 code, you would normally pass by a const& reference if you don't intend to modify the object, or by normal & reference if you need to modify the object. Use a pointer if the parameter is optional.

Some good answers and discussion are also found in these questions, especially the discussion on move semantics:

  • Pass by Reference / Value in C++
  • C++: Reasons for passing objects by value
  • What are move semantics?
  • What's the difference between passing by reference vs. passing by value?

A complete answer for C++11 is more complicated:

  • Is pass-by-value a reasonable default in C++11?

Probably the best summary of which approach to use:

  • How to pass objects to functions in C++?
like image 185
gavinb Avatar answered Sep 22 '22 01:09

gavinb