Reputation: 16701
Given example:
#include <iostream>
#include <cstdlib>
#define PRINT_NAME { std::cout << __PRETTY_FUNCTION__ << std::endl; }
namespace
{
struct A
{
A() { PRINT_NAME; }
~A() { PRINT_NAME; }
};
A f() { return {}; }
A b;
A && g() { return std::move(b); }
}
int
main()
{
std::cout << "------------------" << std::endl;
{
f();
std::cout << 1 << std::endl;
}
std::cout << "------------------" << std::endl;
{
A && a = f();
// or A const & a = f(); as mentioned in below discussion
std::cout << 2 << std::endl;
}
std::cout << "------------------" << std::endl;
{
A && a = g();
std::cout << 3 << std::endl;
}
std::cout << "------------------" << std::endl;
return EXIT_SUCCESS;
}
and its output (of clang 3.5.0):
(anonymous namespace)::A::A()
------------------
(anonymous namespace)::A::A()
(anonymous namespace)::A::~A()
1
------------------
(anonymous namespace)::A::A()
2
(anonymous namespace)::A::~A()
------------------
3
------------------
(anonymous namespace)::A::~A()
What is the semantic rule: an thinkable shortand of the standard's paragraphs, which compactly summarizes the difference in destructors behaviour regarding above code sample? I often faces "idiomatic rules" formulated via the "have some (non-obviously relevant) characteristic" or "have some inherent attribute" statements, e.g. "if it has a name, then it is an lvalue". Is there something similar?
Upvotes: 4
Views: 497
Reputation: 41301
This has nothing to do with rvalue references. In fact, if you change A&&
to const A&
throughout the code, the behavior won't change.
Probably your confusion is caused by the name of std::move()
function. It doesn't actually move anything, it just casts its argument to rvalue reference.
Don't think about destructors, think about lifetime of objects. Personally I don't know a simple rule of thumb (apart from "read the standard"), but these three rules may help you:
Upvotes: 4