Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it safe to take the address of a temporary?

In my program, I would like to take the address of a temporary. Here is an example:

#include <iostream>

struct Number {
    int value;
    Number(int n) {
        value = n;
    }
};

void print(Number *number) {
    std::cout << number->value << std::endl;
}

int main() {
    Number example(123);
    print(&example);
    print(&Number(456)); // Is this safe and reliable?
}

This would output:

123
456

To compile, the -fpermissive flag is requied.

Here is my question: is this safe and reliable? In what possible case could something go wrong?

like image 515
Luke Avatar asked Apr 07 '18 00:04

Luke


2 Answers

If your definition of "safe and reliable" includes "will compile and produce the same results if the compiler is updated" then your example is invalid.

Your example is ill-formed in all C++ standards.

This means, even if a compiler can be coerced to accept it now, there is no guarantee that a future update of your compiler will accept it or, if the compiler does accept the code, will produce the same desired effect.

Most compiler vendors have form for supporting non-standard features in compilers, and either removing or altering support of those features in later releases of the compiler.

Consider changing your function so it accepts a const Number & rather than a pointer. A const reference CAN be implicitly bound to a temporary without needing to bludgeon the compiler into submission (e.g. with command line options). A non-const reference cannot.

like image 126
Peter Avatar answered Sep 17 '22 15:09

Peter


&Number(456) is an error because the built-in & operator cannot be applied to an rvalue. Since it is an error, it is neither safe nor reliable. "What could go wrong" is that the code could be rejected and/or behave unexpectedly by a compiler which follows the C++ Standard. You are relying on your compiler supporting some C++-like dialect in which this code is defined.


You can output the address of the temporary object in various ways. For example add a member function auto operator&() { return this; } . The overloaded operator& can be applied to prvalues of class type.

Another way would be to have a function that is like the opposite of move:

template<typename T>
T& make_lvalue(T&& n)
{
     return n;
}

and then you can do print(&make_lvalue(Number(456)));

If you are feeling evil, you could make a global template overload of operator&.

like image 37
M.M Avatar answered Sep 21 '22 15:09

M.M