Question

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?!

Was it helpful?

Solution

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:

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:

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

Probably the best summary of which approach to use:

OTHER TIPS

Your professor is just flat out wrong, maybe he was thinking about JAVA or C#? Everything is passed by value in C++. To pass something by reference you need to pass it with the & modifier.

Non-primitive types can indeed be passed by value in C++. If you try to do this, C++ will use a special function called the copy constructor (or in some cases in C++11, the move constructor) to initialize the parameter as a copy of the argument. Writing copy constructors and assignment operators is known to be a tricky part of C++ (getting it wrong is easy and getting it right is hard), so it may be the case that the professors were trying to discourage you from doing so. Failing to write a copy constructor or doing so incorrectly can easily lead to program crashes and is a common source of confusion for new C++ programmers.

I'd suggest doing a Google search for "C++ Rule of 3" or "copy constructor assignment operator" to learn more about how to write functions that copy objects intelligently. It takes a bit to get up to speed with how to do this, but once you understand the concepts it's not too hard.

Hope this helps!

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top