The Difference Between Const T& and T in Function Return

I am confused with const T& and T in function return.

For example, I have a class A:

class A {
  private:
    vector<T> my_vector_;
  public:
    T fun1() {
      return my_vector_.at(0);
    }
    const T& fun2() {
      return my_vector_.at(0);
    }
}

Then,

Class A a;
T b = a.fun1();
const T& c = a.fun1();
const T& d = a.fun2();

What's the difference for these three case? Thank you.

1

2 Answers

T b = a.fun1();

Here, b holds a copy of the element at position 0 of the vector. Meaning, any modification made to the former won't affect the latter.

const T& c = a.fun1();

fun1 returned an object by value, and you've used a reference to const to refer to it. Taking this into account, the object is really "floating in space". Its lifetime will be bound to that of c, but is't still a copy of the original from the vector.

const T& d = a.fun2();

fun2 returned a reference to const to an element inside of the vector, and you bound d to it. From now on, the latter is an alias to the former.

2

When you return an object by reference (i.e. T& fun(...) { ...}) then you are returning the same object that you were using inside your function, while when you return the object by value (i.e. T fun(...) { ...}) the object is copied before returning the function.

You can check this if you print your object's memory address inside the function and after it has been returned:

printf("%p\n", &my_object);

The const only says that the compiler should make sure you are not modifying the object from the outside (i.e. you cannot do: object.field = value).

I have arranged this sample that shows all the differences between those approches:

#include <stdio.h>

class X {
    public:
        int i;

        X();
        X(const X&);
};

// Copy constructor
X::X(const X& x) {
    printf("Copy constructor invoked\n");
}

// Default constructor
X::X() : i(0) {
    printf("Creating a object\n");
}

X my_fun_1(X& x) { return x; }
X& my_fun_2(X& x) { return x; }
const X& my_fun_3(X& x) { return x; }

int main () {
    X x0;

    printf("\nInvoke my_fun_1\n");
    X x1 = my_fun_1(x0);

    printf("\nInvoke my_fun_2\n");
    X& x2 = my_fun_2(x0);

    printf("\nInvoke my_fun_3\n");
    const X& x3 = my_fun_3(x0);

    printf("\nResults:\n");
    printf("x0 => %p\n", &x0);
    printf("x1 => %p\n", &x1);
    printf("x2 => %p\n", &x2);
    printf("x3 => %p\n", &x3);

    x0.i = 1;
    x1.i = 1;
    x2.i = 1;
    //Compile-time error: x3.i = 1;

    return 0;
}

Compile and run it, the output should be:

$ g++ a.cpp && ./a.out
Creating a object

Invoke my_fun_1
Copy constructor invoked

Invoke my_fun_2

Invoke my_fun_3

Results:
x0 => 0x7fff8710cce0
x1 => 0x7fff8710ccf0
x2 => 0x7fff8710cce0
x3 => 0x7fff8710cce0

Notice:

  • If you don't use & then the copy constructor is used
  • If you use const then modifying the returned object using that reference is a compile-time error.
1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Chloe Bennett

Chloe Bennett

Culture, Media & Entertainment Columnist

Chloe Bennett explores the intersection of pop culture, streaming entertainment, digital trends, and contemporary lifestyle. Her weekly commentary reaches thousands of culture enthusiasts.

Share this article
Twitter Facebook Pinterest