When will the destructor be called? - c++

#include <memory>
#include <iostream>
class Token { public:
Token() { std::cout << "Token()"; }
~Token() { std::cout << "~Token()"; }
};
template <class T>
std::unique_ptr<T> foo(T t0) {
return std::unique_ptr<T>(new T(t0)); };
int main() {
Token&& t = Token();
auto ptr = foo<Token>(t);
return 0;
}
On which occasions will the destructor be called?
I think it will be called firstly when we call Token(), it creates a temporary object which is destructed immediately, then in the foo() function when t0 is destructed, and then when main() ends, and ptr goes out of scope.
But my friend says otherwise, so how will it actually be?

When a scope ends and the automatic objects of that scope are destroyed, their destructors will be called in the reverse order the objects were created:
int main() {
Token&& t = Token(); // Token1 constructed
// lifetime of Token1 extended because it was bound to t
auto ptr = foo<Token>(t); // creates a copy of Token1 for the argument of foo: Token2
// Token3 constructed by foo in dynamic memory
// and bound to ptr, which
// resides in automatic memory
// Token2 (temporary copy) is automatically destroyed
return 0;
// Last automatic object is destroyed: ptr
// thus, uniqe_ptr destroys Token3
// t is destroyed. This destroys Token1 because
// its lifetime-extending reference
// went out of scope
}
Demo
If you modify your Token class slightly you can observe this live:
class Token {
inline static int C = 1;
int c = C++;
public:
Token(Token const&) : Token() {}
Token(Token&&) : Token() {}
Token() { std::cout << "Token(" << c << ")\n"; }
~Token() { std::cout << "~Token(" << c << ")\n"; }
};
Output:
Token(1)
Token(2)
Token(3)
~Token(2)
~Token(3)
~Token(1)
(live demo)

#bitmask's explanation about life-time is pretty clear. Besides, if you want to get the best performance, maybe you could implement the move constructor for your class Token, and then:
template <class T>
std::unique_ptr<T> foo(T& t0) { // pass-by-reference
return std::make_unique<T>(std::move(t0));
};
As you have used rvalue reference Token&& t to extend the temporary Token object's lifetime in function int main() and the rvalue reference t is a lvalue, so auto foo(T &) will deduce T as class Token and accept t as its parameter t0 according to Overload resolution. Furthermore, std::move cast lvalue t0 to rvalue reference and std::make_unique call the constructor which satisfies std::is_nothrow_constructable_v<Token,Token&&> is true, the move constructor and copy constructor are both candicate functions. If you have implemented Token(Token&&), move constructor will be called. Otherwise is copy constructor.

Related

const class can extend lifetime of const member ref of temporary?

struct A {
// something
~A() { std::cout << "A destruct!\n"; }
};
class refWrapper {
public:
refWrapper(const A& a) : a_(a) {}
~refWrapper() { std::cout << "refWrapper destruct!\n"; }
private:
const A& a_;
};
void func(const refWrapper& ref = A()) {
// why ~A after ~refWrapper
// Rather than after refWrapper constructor complete
}
With default arguments, the call
func();
is equivalent to
func(A()); // so func(refWrapper(A()));
So,
temporary A is created first (destroyed at end of full expression)
temporary refWrapper is created second (bound to parameter reference)
temporary refWrapper destroyed.
temporary A destroyed.
Notice that there is an exception for lifetime extension or parameter:
A temporary object bound to a reference parameter in a function call ([expr.call]) persists until the completion of the full-expression containing the call.
So refWrapper is destroyed at end of full expression, and not at the end of func call (which is the same moment in given example though). So destruction should be done in reverse order of construction.

What's the lifetime of the parameter of a coroutine

#include <iostream>
#include <experimental/coroutine>
#include <string>
#include <thread>
struct InitialSuspend{
bool await_ready(){
return false;
}
bool await_suspend(std::experimental::coroutine_handle<> h){
return false;
}
void await_resume(){
}
};
struct FinalSuspend{
bool await_ready() noexcept{
return false;
}
void await_suspend(std::experimental::coroutine_handle<> h) noexcept{
std::cout<<"FinalSuspend await_suspend\n";
}
std::string await_resume() noexcept{
std::cout<< "await_resume for FinalSuspend\n";
return "await_resume for FinalSuspend\n";
}
};
struct Task{
struct promise_type;
using coroutine_type = std::experimental::coroutine_handle<promise_type>;
struct promise_type{
auto initial_suspend(){
return InitialSuspend{};
}
void unhandled_exception(){
std::cout<<"unhandled_exception\n";
std::terminate();
}
auto final_suspend() noexcept{
return FinalSuspend{};
}
// void return_value(std::string const& v){
// value_ = v;
// }
void return_void(){
}
auto get_return_object(){
return Task{coroutine_type::from_promise(*this)};
}
std::string value_;
};
coroutine_type handler_;
};
struct AwaitAble{
bool await_ready(){
return false;
}
void await_suspend(std::experimental::coroutine_handle<> h){
std::cout<<"await_suspend\n";
}
std::string await_resume(){
std::cout<<"await_resume\n";
return "abc";
}
};
struct Observe0{
Observe0(int v):id_(v){
std::cout<< id_ <<" constructor0\n";
}
~Observe0(){
std::cout<< id_ <<" destroy0\n";
}
Observe0(Observe0 const& v):id_(v.id_+1){
std::cout<< id_<<" copy constructor0\n";
}
Observe0(Observe0&& v):id_(v.id_+1){
std::cout<< id_<<" move constructor0\n";
}
int id_;
};
Task MyCoroutine(Observe0 p){
auto r1 = co_await AwaitAble{};
}
int main(){
Observe0 aa{1}; //#1
auto r = MyCoroutine(aa); //#2
std::cout<<"caller\n";
r.handler_.resume();
r.handler_.destroy();
std::cin.get();
}
The output is:
1 constructor0
2 copy constructor0
3 move constructor0
await_suspend
2 destroy0
caller
await_resume
FinalSuspend await_suspend
3 destroy0
1 destroy0
We can observe the creation or destruction of an object by using the above code. The first print occurs at #1, which constructs the object a. The second print occurs at the initialization of the coroutine parameter at #2. The third print occurs at the initialization of the coroutine parameter copy, which is ruled by the following rules:
[dcl.fct.def.coroutine#13]
When a coroutine is invoked, after initializing its parameters ([expr.call]), a copy is created for each coroutine parameter. For a parameter of type cv T, the copy is a variable of type cv T with automatic storage duration that is direct-initialized from an xvalue of type T referring to the parameter.
These three objects all have their unique number which is convenient to observe the lifetime of the associated object. According to the fifth print, the destructor is called for the coroutine parameter whose name is p. However, according to [expr.await#5.1]
Otherwise, control flow returns to the current coroutine caller or resumer ([dcl.fct.def.coroutine]) without exiting any scopes ([stmt.jump]).
It means that suspend the coroutine and transfer the control to the caller, the parameter scope of the coroutine is not considered exit. Hence, the lifetime of the parameter should not end. Why is the destructor of the parameter called after the first transferring to the caller of the coroutine? Should it be considered a bug in the compiler?
The lifetime of a parameter is not part of the function's scope; it's part of the caller's scope:
The initialization and destruction of each parameter occurs within the context of the calling function.
This is the entire reason why [dcl.fct.def.coroutine#13] exists. In order for a coroutine to preserve its parameters, it has to own them. Which means it must copy/move them from the parameters into local automatic storage.

Return rvalue reference from function

CPP Core guidelines F45 states:
Don't return a T&&.
I want to create some class, and pass the class through a sequence of functions that modify the class. Then I will either evaluate some members of that class, or store the class in some container, like std::vector.
I am trying to do this in a way that the class is constructed exactly once, then destroyed, or moved and the moved-from copy is destroyed, and later the stored copy is destroyed (when the container that I stored it in is destroyed).
In essence, I want to do this:
// some class
class foo{}
// construct a foo, with some parameters, and modify it somehow
auto f1 = modify_foo(foo(x, y, z));
// modify the foo some more
auto f2 = modify_foo(f1);
// modify the foo some more
auto f3 = modify_foo(f2);
// use some element of modified foo
auto v = f3.getx();
// maybe store the modified foo in a vector or some other container
vector<foo> vf;
vf.emplace_back(f3);
It should be possible to construct the foo exactly once, and move the constructed foo through any number of modifying functions, then destroy the foo exactly once.
In the case of storing the foo in a vector, an additional copy/move and destroy will have to occur.
I can achieve this behavior, but I can't figure out any way to do it without using this signature for the modify functions:
foo&& modify_foo(foo&& in);
Here is test code that seems to do what I want:
#include <iostream>
#include <functional>
#include <vector>
// A SIMPLE CLASS WITH INSTRUMENTED CONSTRUCTORS
class foo {
public:
// default constructor
foo() {
std::cout << "default construct\n";
}
// copy constructor
foo(foo const &in) : x{ in.x } {
std::cout << "copy construct\n";
};
// copy assignment
foo& operator=(foo const& in) {
x = in.x;
std::cout << "copy assignment\n";
}
// move constructor
foo(foo&& in) noexcept : x(std::move(in.x)) {
std::cout << "move constructor\n";
}
// move assignment
foo& operator=(foo&& in) noexcept {
x = std::move(in.x);
std::cout << "move assignment\n";
return *this;
}
// destructor
~foo() {
std::cout << "destructor\n";
}
void inc() {
++x;
}
int getx() { return x; };
private:
int x{ 0 };
};
Now a function that will take foo&&, modify foo, return foo&&:
// A SIMPLE FUNCTION THAT TAKES foo&&, modifies something, returns foo&&
foo&& modify(foo&& in) {
in.inc();
return std::move(in);
}
Now using the class and modify function:
int main(){
// construct a foo, modify it, return it as foo&&
auto&& foo1 = modify(foo());
// modify foo some more and return it
auto&& foo2 = modify(std::move(foo1));
// modify foo some more and return it
auto&& foo3 = modify(std::move(foo2));
// do something with the modified foo:
std::cout << foo3.getx();
}
This will do exactly what I want. It will call the constructor once, correctly print 3, and call the destructor once.
If I do the same thing, except add this:
std::vector<foo> fv;
fv.emplace_back(std::move(foo3));
It will add one move construct, and another destruct when the vector goes out of scope.
This is exactly the behavior I want, and I haven't figured out any other way to get there without returning foo&& from the modifier, and using auto&& for my intermediate variables, and using std::move() on the parameters being passed to the subsequent calls to modify.
This pattern is very useful to me. It is bothering me that I can't resolve this with CPP core guidelines F.45. The guideline does say:
Returning an rvalue reference is fine when the reference to the temporary is being passed "downward" to a callee; Then the temporary is guaranteed to outlive the function call...
Maybe that is what I am doing?
My questions:
Is there anything fundamentally wrong, or undefined, in what I am doing?
When I do auto&&, and hover over the foo1, it will show it as a foo&&. I still have to wrap the foo1 with std::move(foo1) to get the modify function to accept it as foo&&. I find this a little strange. What is the reason for requiring this syntax?
As was correctly pointed out by NathanOliver, attempting to use rvalue ref's was leaving a dangling reference to an object that was being destroyed at the end of the function's life.
The piece of the puzzle that I was missing was to use 'auto&', instead of 'auto' when returning a ref from a function:
// function taking lvalue ref, returning lvalue ref
foo& modify(foo& in) {
in.inc();
return in;
}
{
auto f = foo{}; // constructed here
auto f1 = modify(f); // <-- BAD!!! copy construct occurs here.
auto& f2 = modify(f); // <-- BETTER - no copy here
} // destruct, destruct
If I use auto& to capture the lvalue ref returning from 'modify', no copies are made. Then I get my desired behavior. One construct, one destruct.
{
// construct a foo
foo foo1{};
// modify some number of times
auto& foo2 = modify(std::move(foo1));
auto& foo3 = modify(std::move(foo2));
auto& foo4 = modify(std::move(foo3));
std::cout << foo4.getx();
} // 1 destruct here

Forward reference confusion

With reference to the following code, I do not understand why the move constructor is called both with an lvalue and rvalue. I would expect copy ctor to be printed when i pass an lvalue to the push method.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class my_obj
{
public:
my_obj()
{
cout << "default ctor\n";
}
my_obj(const my_obj& other)
{
cout << "copy ctor\n";
}
my_obj(my_obj&& other)
{
cout << "move ctor\n";
}
};
class test
{
public:
template<typename T>
void push(T&& object)
{
print(forward<T>(object));
}
template<typename T>
void print(T&& a)
{
cout << "move\n";
my_obj temp = forward<T>(a);
}
template<typename T>
void print(T& a)
{
cout << "val\n";
my_obj temp = forward<T>(a);
}
};
int main()
{
my_obj obj;
test f;
f.push(obj); // why is move ctor called here? shouldnt it be copy ctor since not rvalue
cout << "\nPUSHING TEMP\n\n";
f.push(my_obj {});
}
output:
default ctor
val
move ctor
PUSHING TEMP
default ctor
move
move ctor
In here:
template<typename T>
void print(T& a)
{
cout << "val\n";
my_obj temp = forward<T>(a);
}
a isn't a forwarding reference, it's an lvalue reference. The type T isn't a reference type. So forward<T>(a) behaves the same as move(a). The special case for forwarding references is that the template parameter deduces to a reference type, and forwarding with a reference type yields an lvalue.
You just want my_obj temp = a;
The move constructor is called because you are using std::forward without a forwarding reference (don't do that please). Basically, this line is the culprit:
my_obj temp = forward<T>(a);
Here, T is a my_obj. Remember that std::forward is just a glorified cast. In your case, it is equivalent to:
my_obj temp = static_cast<my_obj&&>(a);
So you are casting a to a rvalue reference, and an rvalue has move semantics, so you see the move constructor being called. You are basically getting the behavior of std::move.

C++ - how to return a prvalue by reference?

So I'm implementing a native arrays wrapper which will allow such to be passed as function arguments and to be returned. I'm having a trouble however with casting it to a native array as native arrays can't be returned. As an replacement I decided to use 'rvalue' reference return type of the casting operator but this will not act correctly because if I want to bind the returned object into an 'rvalue' reference in order to extend it's life-time this won't happen as it's an 'xvalue' and not 'prvalue'. Is there any solution for the problem? Maybe some 'prvalue' cast? Or if there is some other way to implement this implicit cast to 'array'?
The class:
template<typename type>
struct tmp
{
tmp() {}
tmp(const tmp &) = default;
tmp(const type & arg) : tmp(*(const tmp*)arg) {}
&& operator type() && {return static_cast<type&&>(d);}
~tmp () { cout << "tmp destructor" << endl; }
type d;
};
And the code that uses it:
tmp<tmp<int [4]>> Func() // used 'tmp<int [4]>' instead of array to track object destruction (but normally it should be an native array type
{
return tmp<tmp<int [4]>>();
}
int main()
{
tmp<int [4]> &&tmp1 = Func(); //implicit cast (from 'tmp<tmp<int [4]>>') to 'tmp<int [4]>', calls tmp::operator type()
cout << "Here" << endl;
return 0;
}
The program output:
tmp destructor
tmp destructor
Here
As you see the return value of the cast operator is not extended.
Life example.
A prvalue is an rvalue that is not an xvalue, aka "a temporary object or subobject thereof, or a value that is not associated with an object."
You cannot create an array that is a a temporary object (12.2), nor can you create an array value that is not associated with an object.
For an array to be a prvalue, that leaves a subobject thereof of a temporary object.
So a tmp:
template<typename type>
struct tmp
{
tmp() {}
tmp(const tmp &) = default;
tmp(tmp &&) = default;
tmp(const tmp &&o):tmp(o) {}
tmp(tmp &o):tmp(const_cast<tmp const&>(o)){}
template<class... Ts>
tmp(Ts&&...ts) : v{std::forward<Ts>(ts)...} {}
~tmp () { std::cout << "tmp destructor\n"; }
type v;
};
A wrap_as_tmp:
template<class X, class... Ts>
tmp<X> wrap_as_tmp(Ts&&... ts)
{
return {std::forward<Ts>(ts)...};
}
to track destruction we use noisy:
struct noisy {
~noisy() { std::cout << "bang\n"; }
};
Then test:
int main() {
auto&& x = wrap_as_tmp<noisy[4]>().v;
std::cout << "There\n";
}
and note that There outputs before the noisy objects explode.
live example
Note the use of .v at the end of the function call.
If your goal is to avoid that, too bad, you cannot.