0

Is it legal to pass the address of a temporary object to a function that takes a pointer. If not, where in the standard does it say this is UB. Specifically, I would like confirmation that the following code is legal and doesn't contain undefined behavior:

#include <memory>
template <class T>
inline const T* unsafe_addressof(const T&& x) {
    return std::addressof(x);
}

struct S {};

// NOTE: p only used until f returns.
void f(const S* p);

int main() {
    f(unsafe_addressof(S{}));
    return 0;
}
kalc
  • 56
  • 3
  • 2
    Yup, it is. You wont be arrested. – Sv Sv Oct 26 '17 at 16:50
  • @SvSv Are you sure about that? Somebody might write a compiler which frames the programmer for a heinous crime on any UB. I don’t *think* this has UB, though. – Daniel H Oct 26 '17 at 16:57
  • duplicate https://stackoverflow.com/questions/584824/guaranteed-lifetime-of-temporary-in-c – UKMonkey Oct 26 '17 at 16:57
  • or even https://stackoverflow.com/questions/2506793/c-life-span-of-temporary-arguments – UKMonkey Oct 26 '17 at 16:57
  • Also, https://stackoverflow.com/questions/2280688/taking-the-address-of-a-temporary-object – Jodocus Oct 26 '17 at 16:58
  • It's intentionally hard to do... as you note you have to wrap your call to std::addressof in order to make the compiler work. And that's a good thing - this is about language ergonomics. The issue here is about contracts. If you control both pieces of code, this seems fine, but... why? Why not just take it by value in f? You wouldn't have any copies, and the lifetime would be the same. And if you don't control both pieces of code... don't do it. This is depending on a not-great assumption. – wrhall Oct 26 '17 at 17:38
  • @wrhall addressof was modified in C++17 to make it harder. Prior to C++17, simply calling `std::addressof` worked I believe. – Yakk - Adam Nevraumont Oct 26 '17 at 19:22
  • @wrhall I don't control f(), however I don't get your argument why not to do it. If f() lets the pointer escape, then its breaking its contract. And I don't really have a choice. If I used a temporary variable instead, it doesn't help the situation at all. – kalc Oct 26 '17 at 22:06
  • Imagine f is a factory method that returns a result [clearly not true here, but bear with me]. In that case, it would be reasonable for it to take a ptr and store it on the object it creates. If you used a temp that were at scope, then both objects would have the same scope and the new one created by f would be destructed first. – wrhall Oct 27 '17 at 14:48
  • @wrhall and then you return the object and you have issue again. ;-) Of course you must know what the lifetimes are and what references what... On the other hand, what about the argument that passing a temporary directly into a function and avoiding an additional local variable makes the code more readable because it is documenting at the call site that the pointer/reference cannot be used outside of the function otherwise the program would be ill formed.? – kalc Oct 27 '17 at 21:21
  • @kalc it's not necessary for you to return it. You might use it locally [but largely we agree on this, I think]. re: "avoid... additional local variable" - I see the point. You could accomplish this with scopes, but that adds a bunch of whitespace / doesn't necessarily *look* better. Ultimately, if it seems like `f` should own the variable, then it should take it by value or take a unique_ptr. – wrhall Oct 29 '17 at 20:14

1 Answers1

2

Yes, and you don't even have to make it const.

template <class T>
inline std::remove_reference_t<T>* unsafe_addressof(T&& x) {
    return std::addressof(x);
}

struct S {};

// NOTE: p only used until f returns.
void f(const S* p);

int main() {
    f(unsafe_addressof(S{}));
    return 0;
}

Now unsafe_addressof will return a pointer-to-array, pointer-to-temporary, pointer-to-lvalue, or whatever else you try to get it to return a pointer to.

The lifetime of that pointer's validity is the lifetime of the thing pointed to, be it a temporary instantiated out of a prvalue, an xvalue, or an lvalue.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524