1

B在下面的代码中,当执行返回mainfrom时,在案例 1 中调用了类的析构函数,但在案例 2 中没有调用fn()。我不明白这种区别,因为当A使用new. 你能解释一下吗?

class B {
public:
    B() {
        printf(" [B] COntsructor");
    }
    ~B() {
        printf(" [B] Destructor");
    }
};

class A {
public:
    A() { 
        printf(" [A] COntsructor");
    }
    ~A() { 
        printf(" [A] Destructor");
    }

    B Query() { return b; }    /// Case 1
    B* Query() { return &b; }  /// Case 2

    B b;
};

void fn()
{
    A *a = new A();
    B b = a->Query();  // case 1
    B* b = a->Query(); // case 2
    return;
}

int _tmain(int argc, _TCHAR* argv[])
{
    fn();
    return 0;
}
4

4 回答 4

3

情况 1:当您按值返回b时,局部变量b是使用复制构造函数构造的。Return Value Optimization会优化除一份之外的所有副本。局部变量b的析构触发析构函数。

情况 2:当您返回时,您&b返回的只是一个指向的指针b,因此不需要销毁

编辑:代码显示在没有相应调用构造函数的情况下调用析构函数。这是因为函数返回副本是通过复制构造函数发生的。

Edit2:@ZarShardan 是正确的——由于Return Value Optimization ,我提到的“许多副本”可能不存在。

于 2013-01-07T06:42:55.827 回答
1
  • a永远不会被删除,因此它或其成员没有析构函数。
  • a->b将使用默认构造函数构造,所以这就是你看到的构造函数调用。
  • B b = a->Query();将使用不打印任何内容的复制构造函数创建。
  • 在 结束时fn,本地b将超出范围,因此这是您的析构函数调用。

如果您为复制构造函数添加调试代码,如果您让所有调试代码都打印 的值this,并且如果您最终删除a以查看这些析构函数调用,事情可能会变得更清楚。

于 2013-01-07T06:51:05.437 回答
0

我没有看到您在第二种情况下创建了一个new实例,因此 A 作为成员持有的指针将使用' 析构函数B进行清理,并且由于从未调用过构造函数 in ,因此也不会调用析构函数。AB

于 2013-01-07T06:48:43.160 回答
-1

对象 a 永远不会被删除,因此它自己的析构函数和它的成员对象析构函数都不会被调用。

尝试添加

delete a; 

在你的函数 fn() 结束时

或更好地使用 std::unique_ptr 而不是裸指针。这是更好的设计,以防您的 Query 成员函数抛出异常(RAII 的东西)

于 2013-01-07T06:47:47.600 回答