0

下面的一段代码

#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;
}

我希望,在离开中间范围时,向量会破坏并尝试破坏 conatain 中的元组。这反过来破坏了 A 的对象,但有些我看不到任何对象被破坏。Valgrind 也没有显示任何内存错误。以下是使用 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)

我显然在这里遗漏了一些东西。如果在中间范围内对“get()”的调用确实返回了适当的值(100 和 200),为什么在向量(和元组)被破坏时不调用“A”的析构函数?

[编辑] @Howard Hinnant:谢谢,这很有意义。我不明白的是:1)当我用右值构造一个元组并将其推送到向量时,我确实得到了 valgrind 内存错误。例如。

myVec.push_back( std::make_tuple( 10 ) );

在最里面的范围内并添加:

auto& z = get<0>(myVec.at(2));
std::cout << z.get() << std::endl;

到上述示例中的中间范围会产生 valgrind 内存错误,但不会产生上面显示的左值引用。

2) 有人能解释一下为什么下面的语句调用了一个 copu 构造函数和一个直接析构函数吗?

myVec.push_back( std::make_tuple( a ) );
4

1 回答 1

1

'a' 和 'b' 在您离开 Innermost 范围时被破坏,如您的输出所示:

Innermost scope
Destructor 200, this: 0x7fefffc60
Destructor 100, this: 0x7fefffc70
Intermediate scope

get在中间范围内获得的引用是悬空的:它们引用被破坏的对象。有零来确认这一点~A()m_a

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.

于 2011-08-02T13:59:48.260 回答