问题

下面的代码安全吗?里面的临时变量会不会在打印完就释放了?

理论分析

临时变量的生命周期

参考:https://en.cppreference.com/w/cpp/language/lifetime

Temporary object lifetime
Temporary objects are created when a prvalue is materialized so that it can be used as a glvalue, which occurs (since C++17) in the following situations:

binding a reference to a prvalue
initializing an object of type std::initializer_list<T> from a braced-init-list
(since C++11)
returning a prvalue from a function
conversion that creates a prvalue (including T(a,b,c) and T{})
lambda expression
(since C++11)
copy-initialization that requires conversion of the initializer,
reference-initialization to a different but convertible type or to a bitfield.
(until C++17)
when performing member access on a class prvalue
when performing an array-to-pointer conversion or subscripting on an array prvalue
for unevaluated operands in sizeof and typeid
when a prvalue appears as a discarded-value expression
if supported by the implementation, when passing or returning an object of trivially-copyable type in a function call expression (this models passing structs in CPU registers)

精华在这里:
https://en.cppreference.com/w/cpp/language/destructor#Trivial_destructor

Explanation
The destructor is called whenever an object's lifetime ends, which includes

program termination, for objects with static storage duration
thread exit, for objects with thread-local storage duration
(since C++11)
end of scope, for objects with automatic storage duration and for temporaries whose life was extended by binding to a reference
delete-expression, for objects with dynamic storage duration
**end of the full expression, for nameless temporaries**
stack unwinding, for objects with automatic storage duration when an exception escapes their block, uncaught.
The destructor may also be called directly, e.g. to destroy an object that was constructed using placement-new or through an allocator member function such as std::allocator::destroy(), to destroy an object that was constructed through the allocator. Note that calling a destructor directly for an ordinary object, such as a local variable, invokes undefined behavior when the destructor is called again, at the end of scope.

In generic contexts, the destructor call syntax can be used with an object of non-class type; this is known as pseudo-destructor call: see member access operator.

何谓full-expression

参考: https://www.e-learn.cn/topic/2817789

A full-expression is:

[…]

an expression that is not a subexpression of another expression and that is not otherwise part of a full-expression.
If a language construct is defined to produce an implicit call of a function, a use of the language construct is considered to be an expression for the purposes of this definition. […]

实验验证

#include <iostream>
#include <stdio.h>

std::string GetTempStr() {
        return std::string("hello");
}

int main() {
        int a = 5;
        std::cout << GetTempStr().c_str() << std::endl;
        printf("string is %d : %s\n", a, GetTempStr().c_str());
        return 0;
}

输出:
[root@vm10-0-5-23 essd]# ./test
hello
string is 5 : hello

参考

https://stackoverflow.com/questions/5459759/full-expression-boundaries-and-lifetime-of-temporaries?noredirect=1&lq=1 同样也可以看到上面的问题。