Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ temporary object bound to argument and return value const references

Tags:

c++

I cannot get a clear idea of whether this is legal, even after looking at related questions on SO and reading the C++03 standard page 192 (http://cs.nyu.edu/courses/fall11/CSCI-GA.2110-003/documents/c++2003std.pdf). Is this legal and safe:

const MyClass& f(const MyClass& arg) {
  return arg;
}

void some_other_function() {
  const MyClass& reference = f(MyClass());
  // Use reference.
}

It seems to me that it is.

like image 684
aelguindy Avatar asked Aug 04 '14 07:08

aelguindy


2 Answers

As far as I know, you can't do this. While binding a temporary to a const reference is legal C++(and lengthens the lifetime of that temporary -- see GOTW 88), further binding a const ref to another const ref doesn't lengthen the lifetime of that temporary.

The quote from page 192(C++03 standard):

A temporary bound to a reference parameter in a function call (5.2.2) persists until the completion of the full expression containing the call

I think the standard is pretty explicit that using reference after // Use reference. is invalid. I modified your snippet to check it(Mac OS X, clang: Apple LLVM version 5.1 (clang-503.0.40) (based on LLVM 3.4svn)):

#include <iostream>

struct MyClass
{
    ~MyClass()
    {
        std::cout << "~MyClass()" << std::endl;
    }
};

const MyClass& f(const MyClass& arg) {
    std::cout << "f()" << std::endl;
    return arg;
}

int main() {
    const MyClass& reference = f(MyClass());
    std::cout << "main()" << std::endl;
}

It outputs:

f()
~MyClass()
main()

In other words, unless both me and clang developers are misinterpreting the C++ standard, it is illegal.

like image 108
Alexander Putilin Avatar answered Sep 27 '22 20:09

Alexander Putilin


I was unable to get a clear interpretation from the standard, so I decided to check what's the de facto standard. The following code:

#include <cstdio>

struct MyClass
{
    MyClass() { printf("constructor\n"); }
    ~MyClass() { printf("destructor\n");  }
    MyClass(const MyClass&) { printf("copy\n"); }
    MyClass(MyClass&&) { printf("move\n"); }
};

const MyClass& f(const MyClass& arg) {
    return arg;
}

int main()
{
    {
        printf("before construction\n");
        const MyClass& reference = f(MyClass());
        printf("after construction\n");   
    }
    printf("outside scope\n");
}

Yields:

before construction
constructor
destructor
after construction
outside scope

For MSVC, clang and g++. Seems it is not legal according to our main compiler suppliers.

like image 31
gwiazdorrr Avatar answered Sep 27 '22 20:09

gwiazdorrr