The following piece of code
#include <iostream>
#include <vector>
#include <tuple>
using namespace std;
class A {
int m_a;
public:
A(): m_a( 10 ) { std::cout << "Default Constructor " << m_a << ", this: " << this << std::endl; }
A( int a ): m_a( a ) { std::cout << "Main Constructor " << m_a << ", this: " << this << std::endl; }
A( const A& a ): m_a( a.m_a) { std::cout << "Copy Constructor: " << m_a << ", this: " << this << std::endl; }
A( const A&& a ): m_a( std::move(a.m_a) ) { std::cout << "RValue copy Constructor " << m_a << ", this: " << this << std::endl; }
int get() const { return m_a; }
virtual ~A() { std::cout << "Destructor " << m_a << ", this: " << this << std::endl; }
};
int main() {
{
typedef std::tuple< A&& > MyContainer;
std::vector< MyContainer > myVec;
{
A a(100);
A b(200);
myVec.push_back( std::make_tuple( a ) );
myVec.push_back( std::make_tuple( b ) );
std::cout << "Innermost scope" << std::endl;
}
std::cout << "Intermediate scope" << std::endl;
auto& x = get<0>(myVec.at(0));
auto& y = get<0>(myVec.at(1));
std::cout << x.get() << std::endl;
std::cout << y.get() << std::endl;
}
std::cout << "Outermost scope" << std::endl;
return 0;
}
I expect that, upon leaving the intermeidate scope, the vector destructs and it attempts to destruct the tuples in conatain. This in turn destructs the objects of A, but some how I don't see any objects getting destroyed. Valgrind doesn't show any memory errors either. Following is the output when run with valgrind $valgrind ./a.out
==7366== Memcheck, a memory error detector
==7366== Copyright (C) 2002-2009, and GNU GPL'd开发者_开发技巧, by Julian Seward et al.
==7366== Using Valgrind-3.5.0 and LibVEX; rerun with -h for copyright info
==7366== Command: ./a.out
==7366==
Main Constructor 100, this: 0x7fefffc70
Main Constructor 200, this: 0x7fefffc60
Copy Constructor: 100, this: 0x7fefffcb0
Destructor 100, this: 0x7fefffcb0
Copy Constructor: 200, this: 0x7fefffcd0
Destructor 200, this: 0x7fefffcd0
Innermost scope
Destructor 200, this: 0x7fefffc60
Destructor 100, this: 0x7fefffc70
Intermediate scope
100
200
Outermost scope
==7366==
==7366== HEAP SUMMARY:
==7366== in use at exit: 0 bytes in 0 blocks
==7366== total heap usage: 2 allocs, 2 frees, 24 bytes allocated
==7366==
==7366== All heap blocks were freed -- no leaks are possible
==7366==
==7366== For counts of detected and suppressed errors, rerun with: -v
==7366== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
I am obviously missing some thing here. If the calls to "get()" in the intermediate scope do return appropriate values (100 and 200), why aren't the destructors of "A" called when the vector is (and the tuples are) being destructed?
[EDIT] @Howard Hinnant: Thanks and it makes perfect sense. What I don't understand are the following: 1) When I construct a tuple with an rvalue and push it to the vector, I do get valgrind memory errors. For eg.
myVec.push_back( std::make_tuple( 10 ) );
in the inner most scope and adding:
auto& z = get<0>(myVec.at(2));
std::cout << z.get() << std::endl;
to the intermediate scope in the above examples produce valgrind memory errors, but not the lvalue references shown above.
2) Could some one please explain why the following statement is calling a copu constructor and an immediate desctructor?
myVec.push_back( std::make_tuple( a ) );
'a' and 'b' are destructed as you leave the Innermost scope, as your output shows:
Innermost scope
Destructor 200, this: 0x7fefffc60
Destructor 100, this: 0x7fefffc70
Intermediate scope
The references you obtain via get
in the Intermediate scope are dangling: they reference destructed objects. Have ~A()
zero m_a
to confirm this.
As you leave Intermediate scope, the vector and the tuples it holds are destructed. The destructor of a tuple of references is a no-op.
精彩评论