new然后抛出C ++构造函数?

时间:2011-12-28 11:11:04

标签: c++ constructor new-operator throw

如果我这样做

Bat::Bat() : m_member_str(new std::string("Am I freed?"))
{
  throw std::runtime_error("oops");
}

new已分配std::string已被释放?我想这可能是因为没有调用析构函数。

我没有使用std :: string ,而是我自己的类,只是将它作为一个简单的示例显示。

4 个答案:

答案 0 :(得分:3)

此示例是智能指针的经典用例。 Bat未完全构造,因此不会调用析构函数,但m_member_str和所有其他完全构造的成员的析构函数将是。如果你不想要一个像try { foo(); } catch (...) { delete m_member_str; }这样的丑陋块,你必须对RAII感到满意。

std::auto_ptrboost::scoped_ptr将帮助您使用C ++ 03,或者它们在C ++ 11中的等价物。将它们用于拥有的成员指针几乎没有什么缺点。

答案 1 :(得分:3)

完全构造的对象会调用它们的析构函数。 部分构造的对象不会。

在您的情况下,您的Bat对象是部分构造的,因为您从其构造函数中抛出了异常。因此~Bat()被调用。

m_member_str 已完全构造,因此将调用其析构函数 。 但是,我们不可能看到该对象的类型。

如果是std::string*,则不会发生任何事情。它是一个指针,并且销毁指针不会删除它指向的内存。

如果它是某种形式的智能指针,那么它的析构函数将被调用,它将安全地处理你分配的内存。

通常,只要您的成员是RAII对象并拥有有意义的析构函数,无论如何都会清理它们。

如果不是,就像在这种情况下那样,你必须自己处理后果,可能会抓住异常,释放内存然后重新抛出。

答案 2 :(得分:1)

不,除非你照顾它,否则该物体将被泄露。最好的方法是使用智能指针作为成员变量。一般规则是在堆栈展开期间销毁完全构造的对象,同样适用于m_member_str变量,但由于它是一个原始指针,析构函数将是微不足道的,不会触及指向的对象。 / p>

答案 3 :(得分:1)

你完全改变了你的问题 - 使我原来的答案无效! ;-P

  

是否使用new释放了字符串?

没有

  

我在想它可能只是因为没有调用析构函数

不相关。要获得释放,您基本上需要一个构造对象,其中将调用析构函数 ,并且构造函数在其中执行释放(或者您可以使用try / catch块并显式执行)

  

那么我怎样才能释放m_member_str,如果它是成员指针?

(首先,最好的一般方法是使成员变量m_member_str成为字符串而不是指向字符串的指针 - 然后字符串析构函数将清理。)

如果必须有指针,请使用智能指针捕获指针,以便智能指针的析构函数析构指向的对象释放内存。当异常处理期间失败的构造函数销毁已构造的成员变量时,将调用此方法。