Perfect forwarding, why does the destructor get called twice? - c++

I'm trying to make a function that mimics Python's with statement but I've run into some interesting behavior that I don't quite understand.
With the following program:
#include <iostream>
struct foo {
foo() { std::cout << "foo()" << std::endl; }
~foo() { std::cout << "~foo()" << std::endl; }
};
auto make_foo() -> foo {
return {};
}
template <typename T, typename F>
auto with(T&& t, F&& fn) -> void {
fn(std::forward<T>(t));
}
auto main() -> int {
std::cout << "before" << std::endl;
with(make_foo(), [](auto f) {
std::cout << "during" << std::endl;
});
std::cout << "after" << std::endl;
}
When compiled under with the clang provided by Xcode 6.3 and -std=c++14 and run I get the following output:
before
foo()
during
~foo()
~foo()
after
Does anybody know why I am getting two ~foo()'s in my output?

Here are the two objects:
with(make_foo(), [](auto f) {
1^^^^^^^^^ 2^^^^^^
There is the object returned by make_foo(), and the function argument f.
If you pass by reference (change to auto&& f) then you will only see evidence of one object.
There's no creation message because this is created by copy/move construction and you do not have any output in those constructors.
Note that there may be more objects inside make_foo() but your compiler is doing copy elision.

Your destructor calls don't appear to be matched with constructor calls simply because you aren't tracing copy/move constructors. If we add the tracing like so:
struct foo {
foo() { std::cout << "foo()" << std::endl; }
~foo() { std::cout << "~foo()" << std::endl; }
foo(const foo&) { std::cout << "foo(const foo&)" << std::endl; }
foo(foo&&) { std::cout << "foo(foo&&)" << std::endl; }
};
our output is now:
before
foo()
foo(foo&&)
during
~foo()
~foo()
after
The reason for the move-construction is that your lambda takes its parameter by value:
[](auto f) {
// ^^^^^^
std::cout << "during" << std::endl;
}
If you don't want the copy, take by reference-to-const, or maybe even forwarding reference.

This works for me by accepting an r-reference in the lambda function parameter to prevent a copy being made:
#include <iostream>
struct foo {
foo() { std::cout << "foo()" << std::endl; }
~foo() { std::cout << "~foo()" << std::endl; }
};
auto make_foo() -> foo {
return {};
}
template <typename T, typename F>
auto with(T&& t, F&& fn) -> void {
fn(std::forward<T>(t));
}
auto main() -> int {
std::cout << "before" << std::endl;
with(make_foo(), [](auto&&) { // r-reference!
std::cout << "during" << std::endl;
});
std::cout << "after" << std::endl;
}
New Improved Output:
before
foo()
during
~foo()
after

Related

Template variables with class as typename

I am learning C++14, in that come across this template variable feature and that interested me to dig more on this and i tried with multiple examples to understand the template variables. Say,
template <typename T>
T var;
var<int>;
var<float>;
Above code worked and it looked straight forward to understand too. But, when I tried to use class name in place of int or float as shown above, result in calling the temporary object creation for the class FOO and calling corresponding C'tor & dtor for the temp object.
var<FOO>; //FOO is a class
I have written a sample test program and its output for your understanding. My question is that,
Why var creates temp object?
How template variable differ for primitive datatypes and user defined datatypes?
If it is irrelevant or duplicate, please point me to the source for clear understanding.
Refer code below,
class B
{
public:
B()
{
std::cout<<"\nB ctor"<<std::endl;
}
B(const B& obj)
{
std::cout<<"B copy ctor"<<std::endl;
}
int operator()()
{
std::cout<<"operator() called"<<std::endl;
}
void f() {
//::A().print();
}
~B()
{
std::cout<<"\n~ for B()"<<std::endl;
}
};
//Declaring template variable
template<typename T>
T g ;
int main() {
g<int> = 30;
g<float> = 30.02f;
g<B> = B{};
std::cout<<"g value:"<<g<int><<std::endl;
std::cout<<"g value:"<<g<float>;
}
Output:
B ctor
g value:30
g value:30.02
~ for B()
No temporary object is created by this simple program:
int main() {
var<SomeClass>;
}
A temporary object is created here:
int main() {
var<SomeClass> = SomeClass{};
}
but that is because we did it with SomeClass{}. We then assigned that to the var<SomeClass> non-temporary object (global in many of your examples).
The code that runs here is
SomeClass::SomeClass()
SomeClass::SomeClass()
SomeClass::operator=(SomeClass&&)
SomeClass::~SomeClass()
SomeClass::~SomeClass()
in that order.
#include <iostream>
struct noisy {
noisy() { std::cout << __func__ << "()\n"; }
~noisy() { std::cout << __func__ << "()\n"; }
noisy(noisy&&) { std::cout << __func__ << "(&&)\n"; }
noisy(noisy const&) { std::cout << __func__ << "(c&)\n"; }
void operator=(noisy&&) { std::cout << __func__ << "(&&)\n"; }
void operator=(noisy const&) { std::cout << __func__ << "(c&)\n"; }
};
template<class T>
T var;
int main() {
std::cout << "Start of main\n";
{
var<noisy> = noisy{};
std::cout << "Body of main\n";
}
std::cout << "End of main\n";
}
live example.
Output:
noisy()
Start of main
noisy()
operator=(&&)
~noisy()
Body of main
End of main
~noisy()

C++11 move to local const reference: scope [duplicate]

This question already has answers here:
const reference to a temporary object becomes broken after function scope (life time)
(2 answers)
Closed 4 years ago.
For regular local const reference variables, the scope is prolonged. Which is why the following code works as expected:
#include <iostream>
#include <memory>
struct foo
{
foo()
{
std::cout << "foo() #" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() #" << (void*)this << std::endl;
}
};
int main()
{
auto const& f = std::make_shared<foo>();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints:
// foo() #0x55f249c58e80
// f = 0x55f249c58e80
// ~foo() #0x55f249c58e80
It seems though that this does not work as expected when assigning a moved object using std::move():
#include <iostream>
#include <memory>
#include <list>
struct foo
{
foo()
{
std::cout << "foo() #" << (void*)this << std::endl;
}
~foo()
{
std::cout << "~foo() #" << (void*)this << std::endl;
}
};
int main()
{
std::list<std::shared_ptr<foo>> l;
l.push_back(std::make_shared<foo>());
auto const& f = std::move(l.front());
l.clear();
std::cout << "f = " << f.get() << std::endl;
return 0;
}
// prints
// foo() #0x564edb58fe80
// ~foo() #0x564edb58fe80
// f = 0x564edb58fe80
Does std::move() indeed change the scope, or am I dealing with a compiler bug?
Changing the variable from auto const& f to just auto f fixes the problem. If I wrap the move into another function, it also works:
auto const& f = [&]() { return std::move(l.front()); }();
It's almost like std::move() does not share the same semantics as a function call, but rather as if it was just a regular variable assignment:
auto const& f = std::move(l.front());
Let's put aside std::move() and create this function:
struct sometype {};
const sometype &foobar( const sometype &cref ) { return cref; }
and now we use it:
const sometype &ref = foobar( sometype() );
What do you think, will lifetime of temporary be prolongated in this case? No it would not. Lifetime is only prolongated when you assign to a reference directly. When it goes through a function or through static_cast or std::move that prolongation is gone. So you have exactly the same issue with std::move()
struct sometype {
sometype() { std::cout << "ctype()" << std::endl; }
~sometype() { std::cout << "~ctype()" << std::endl; }
};
const sometype &foobar( const sometype &cref ) { return cref; }
int main()
{
const sometype &cref1 = foobar( sometype() );
sometype &&cref2 = std::move( sometype() );
std::cout << "main continues" << std::endl;
}
output:
ctype()
~ctype()
ctype()
~ctype()
main continues
live example
Note: you should not use std::move() on return statement, it does not give you anything.
For your code change. You should remember that std::move() does not move anything. It is done by special assignment operator or constructor (if they provided for a type). So when you write this code:
const type &ref = std::move( something );
there is no constructor nor assignment operator involved and so no moving happens. For actual moving to happen you have to assign it to a variable:
type val = std::move( something );
now moving would happen if possible or copy otherwise.

Simple version of `std::function`: lifetime of function object?

I tried to build a very simple version of std::function. Below the code of a very first version. My question is about the lifetime of the temporary object from the lambda-expression, because I'm actually storing a reference to it. Or is the lifetime of the object prolonged?
It tried to use a copy of the function (T mf instead of const T& mf inside struct F), but that gives an error due to the decaying of the function to a pointer.
#include <iostream>
template<typename T>
struct F {
F(const T& f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
const T& mf;
};
template<typename T>
struct F<T*> {
F(T f) : mf{f} {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
void test() {
std::cout << __PRETTY_FUNCTION__ << '\n';
mf();
}
T* mf;
};
void g() {
std::cout << __PRETTY_FUNCTION__ << '\n';
}
int main() {
F<void(void)> f1(g);
f1.test();
auto g1 = g;
F f2(g1);
f2.test();
F f3([](){ // lifetime?
std::cout << __PRETTY_FUNCTION__ << '\n';
});
f3.test();
auto l1 = [](){
std::cout << __PRETTY_FUNCTION__ << '\n';
};
F f4(l1);
f4.test();
}
You do have lifetime problems here: lifetime extension thanks to const only applies for local const references.
You need to make sure that the referenced function lives at least as long as the wrapper, or you need to copy/move the function into the wrapper.
but that gives an error due to the decaying of the function to a pointer
You can use std::decay_t<T> to ensure that you're copying/moving objects (e.g. closures) into the wrapper.

Switching between specialization and overloading

from the code below, I get the following output:
Call member_function
Derived member function
Call template_function
template function
Derived member function
As expected, the specialization of template_function is not called here because derived is of type Base*, but the correct version of member_function is called.
However, sometimes, it may be useful to call not-member functions in template functions.
Does exist a way to ensure that the specialized version of the template function will be called when dynamic instances of Derived class are declared as being of type Base*?
Thanks!
#include <iostream>
// Base and Derived classes
class Base
{
public:
virtual void member_function() const
{ std::cout << "Base member function" << std::endl; };
};
class Derived : public Base
{
public:
virtual void member_function() const
{ std::cout << "Derived member function" << std::endl;};
};
// Functions
template<typename T>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
template<>
void template_function(Derived const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
// Main
int main ()
{
Base * derived = new Derived();;
std::cout << "Call member_function" << std::endl;
derived->member_function();
std::cout << std::endl;
std::cout << "Call template_function" << std::endl;
template_function(*derived);
}
You can add two templates template_function that you enable_if on std::base_of<T, Derived>, like this
// Functions
template<typename T, std::enable_if_t<not std::is_base_of<T, Derived>::value>* = nullptr>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
template<typename T, std::enable_if_t<std::is_base_of<T, Derived>::value>* = nullptr>
void template_function(T const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
// Main
int main ()
{
Base const * base = new Base();
Base const * derived = new Derived();
std::cout << "Call member_function" << std::endl;
base->member_function();
derived->member_function();
std::cout << std::endl;
std::cout << "Call template_function" << std::endl;
template_function(*base);
template_function(*derived);
}
Live Example.
Alternatively, and much simpler, you can simply add a template_function(Base const&) overload
// Functions
template<typename T>
void template_function(T const & arg)
{
std::cout << "template function" << std::endl;
arg.member_function();
}
void template_function(Base const & arg)
{
std::cout << "Specialized function" << std::endl;
arg.member_function();
}
Live Example

Template function is used instead of typed

I have this code:
#include <iostream>
#include <string>
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
Foo(Foo&) {
std::cout << "copy" << std::endl;
}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
Foo f;
Foo f2 (f);
}
It prints "copy", which is correct.
However if I remove the Foo(Foo&):
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
//Foo(Foo&) {
// std::cout << "copy" << std::endl;
//}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
Foo f;
Foo f2 (f);
}
it prints "template". I expected it to print "copy2" because it is typed parameters. Why is it using template instead?
In order to perform overload resolution, the compiler needs to evaluate the constructor template using template argument deduction. So it creates a constructor like this:
template<>
Foo<Foo>::Foo(Foo&);
This constructor takes an lvalue reference to non-const, as oppose to the non-template constructor. This is preferred because an identity conversion (i.e no conversion) is preferred over a qualification conversion.
Foo f;
f is not a const object of Foo. So its type match to following function and it will print template.
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
If you define f as follows, it will print as you expected.
const Foo f;
For the same reason that your first code sample doesn't print copy2. The f you are referencing is not const, so the compiler first tries non-const references. Overload matching matches template<typename T=Foo> Foo(T&) giving an exact match while Foo(const Foo&) requires a cv-adjustment of the parameter being passed.
Try the following:
#include <iostream>
class Foo {
public:
Foo(){};
template<typename T>
Foo (T&) {
std::cout << "template" << std::endl;
}
//Foo(Foo&) {
// std::cout << "copy" << std::endl;
//}
Foo(const Foo&) {
std::cout << "copy2" << std::endl;
}
};
int main(){
const Foo f;
Foo f2 (f);
}
http://ideone.com/zOf1qX