4

I have two code segments which I expected the same outcome:

First one:

SomeClass somefunc(...){
    SomeClass newObj;
    //some codes modify this object
    return newObj;
}

int main(){
    SomeClass *p;
    p = &(somefuc(...));
}

Second one:

SomeClass *somefunc(...){
    SomeClass newObj;
    //some codes modify this object
    return &newObj;
}

int main(){
    SomeClass *p;
    p = somefunc(...);
}

Why is it I got a "taking the address of a temporary object" error when I tried to build the first code segment, while the second code segment doesn't produce an error?

rickie
  • 67
  • 1
  • 6
  • please show your actual code. – tenfour May 04 '15 at 14:35
  • 3
    Neither fragment compiles. The second because you try to return `SomeClass*` from the function declared to return `SomeClass`. Note also that `newObj` is not a temporary - it's a named variable. There is no problem taking its address - the problem lies in *using* said address after the variable's lifetime ends. – Igor Tandetnik May 04 '15 at 14:35
  • the second example shouldn't even compile, and also `p = &(somefuc(...));` shouldn't compile as you cannot take the address of a rvalue – vsoftco May 04 '15 at 14:35
  • 2
    @BaummitAugen That problem is definitely present (in the second example), but not related to the question at hand (in the first example). Not a duplicate. – Paul Roub May 04 '15 at 14:37
  • I guess you meant `SomeClass *somefunc(...){` in your second example? – Baum mit Augen May 04 '15 at 14:37
  • maybe this question can be concluded as: the 'newObj' object is still in memory before main method ends, but why I cannot get the address of 'newObj' outside the 'someFunc' function ? – rickie May 04 '15 at 14:38
  • If that's your question, then Baum mit Augen's duplicate link answers it. – interjay May 04 '15 at 14:39
  • Then edit your question. – interjay May 04 '15 at 14:40
  • @rickie pick the function you *want* to use, and ask about it. One of these is evil on the callee side (the second), while the other is evil on the caller side (the first). – WhozCraig May 04 '15 at 14:41

3 Answers3

4

Before you even think about this, you need to learn the rules of temporary lifetime.

The broad case is that a temporary object is destroyed at the end of the full-expression creating it. The implication is that if

SomeClass *p;
p = &(somefunc(...));

were allowed to work, p would be a dangling pointer, targeting an object that no longer exists.

The big exception to the above rule is that when a reference with automatic lifetime is directly bound to the temporary object, the lifetime of the temporary is extended to be equal to the lifetime of the reference. Note that this does not cover const T& make_lvalue(const T& t) { return t; } because the reference isn't binding directly, nor class member references.

There are a few cases which are completely safe, in which the address of the temporary is only used immediately and not stored for later. e.g.

memcpy(buffer, &f(), sizeof(decltype(f())));

Of course, this results in the "address of a temporary" error you're encountered, but in C++11 and C++14, you can work around it via

memcpy(buffer, std::addressof(f()), sizeof(decltype(f())));

But do NOT store the resulting pointer.

Ben Voigt
  • 277,958
  • 43
  • 419
  • 720
  • Ben is this `std::addressof(f())` guaranteed to be valid by the standard if used immediately in the function? Sorry for beating a dead horse. – Super-intelligent Shade Jun 02 '23 at 03:14
  • Actually, it doesn't even work: https://godbolt.org/z/q5bP6eY54. Because `std::addressof(const T&&)` is deleted. Ref: https://rb.gy/hmakb – Super-intelligent Shade Jun 02 '23 at 03:29
  • 1
    @Super-intelligentShade: That changed two years after this answer was written. Will edit in the versions of C++ for which the hacky workaround is accepted. – Ben Voigt Jun 02 '23 at 14:23
  • Your first comment I think is adequately explained by the second paragraph -- the temporary will exist, and its address will be valid, only within the same statement. – Ben Voigt Jun 02 '23 at 14:26
  • Is that because it is part of the [full-expression](https://en.cppreference.com/w/cpp/language/expressions#Full-expressions)? I am asking because my other solution with the `ptr` wrapper works, but I don't know if I am potentially shooting myself in the foot – Super-intelligent Shade Jun 02 '23 at 14:29
  • 1
    @Super-intelligentShade: Yes, your `ptr` workaround is fine for the same reasons that `std::addressof` used to be ok in my `memcpy` example. The full expression consists of a function call expression, so the entire called function executes within "the lifetime of that expression" (which is a made-up concept) and therefore also within the lifetime of the temporary objects (which is what the Standard concerns itself with). – Ben Voigt Jun 02 '23 at 14:35
2

The first snippet does rightfully not compile because, as the compiler said, you cannot take the address of a temporary object because it would be destroyed at the end of the expression (here: the assignment). Thus, saving its address would be meaningless.

The second snippet does compile, but is still incorrect although it might seem to work for the reasons stated here (at least if you try to access the object through the pointer).

Community
  • 1
  • 1
Baum mit Augen
  • 49,044
  • 25
  • 144
  • 182
0

The first example does not compile because somefunc returns a value, and you attempt to take the address of this temporary thing it returns. This would work:

Someclass* p;
Someclass  val = somefunc (...);
p = &val;

The second example does not compile -- or shouldn't -- because somefunc is supposed to return a Someclass, but instead it returns a pointer to a Someclass. Make it return Someclass* and then it should compile -- but now you're returning a pointer to a local variable, which no longer exists after you leave the function. Best solution is the first example, as patched here.

Topological Sort
  • 2,733
  • 2
  • 27
  • 54