使用std :: uninitialized_copy的Stroustrup示例中的资源泄漏?

时间:2014-07-21 07:56:57

标签: c++

在Stroustrup一书( C ++编程语言4th ed。,§17.5.1,pag 508)中,我找到了以下一个简单Matrix类的复制构造函数示例:

template < class T >
Matrix:: Matrix( const Matrix& m ) // copy constructor
    : dim{ m.dim },
      elem{ new T[ m.size() ] }
{
    uninitialized_copy( m.elem, m.elem+m.size(), elem ); // copy elements
}

(其中elem是指向T元素数组的指针,声明为T* elem;)。

我对这个拷贝构造函数有两个问题:

  1. 为什么方法首先默认构造一个m.size()元素数组,只是用uninitialized_copy调用在身体中覆盖它?

  2. 初始化elem{ new T[ m.size() ] }时,T的构造函数被称为m.size()次。但是,在同一区域中构造新数组之前,正文中的算法uninitialized_copy不会调用T析构函数。这是潜在的资源泄漏吗? (注意:不是内存泄漏,资源泄漏!例如,如果T在ctor中获取锁或文件描述符并在dtor中释放它。)

  3. 由于

2 个答案:

答案 0 :(得分:5)

我是这个问题的作者 我通过电子邮件向 Bjarne Stroustrup 提出了两个问题,并想在这里分享他的答案。

他好心(并且很快:-)回答:

  1. 这是一种疏忽和浪费。
  2. 是的,如果类型T拥有资源,那就是泄漏
  3. 他还写道,他将修复错误。

答案 1 :(得分:3)

是的,这显然是一个错误;代码应使用copy而不是uninitialized_copy。由于T通常是一个微不足道的类型,通常会避免资源泄漏,但它仍然是一个错误。

要回答您的第一个问题,编写复制构造函数成员初始化程序默认构造数组更简单,因为这允许复制构造函数使用与(n, m)构造函数相同的简单分配方法。将未初始化的内存区域和构造分配到其中会更有效,但这会使构造函数和析构函数复杂化,这会降低Matrix类的要点。写这个的更惯用的方法是使用Matrix包装动态数组(固定大小向量)类,例如dynarray(可能是后C ++ 14 TS)。

正如Puppy指出的那样,复制构造函数如果它的主体抛出则会发生内存泄漏。无论是使用copy还是uninitialized_copy,都会发生这种情况。 // simplified (no error handling),所以这可以原谅。

猜测一下,我说这个错误悄悄的方式是Stroustrup在本书的其他地方使用uninitialized_copy,特别是在他的矢量类中。我无法访问旧版本,但我怀疑这是为了在向量复制构造函数中替换循环和try / catch块而添加的,并且在没有充分考虑的情况下对Matrix进行了类似的修改。

第4版没有在Stroustrup的list of errata上展示,但他可能已经知道了(勘误页最后更新于2013年11月)。如果您想通过电子邮件向他发送此错误,您肯定应该这样做!