如果在这段代码中分配失败,内存会泄漏吗?

问题描述

所以对于我的家庭作业,我不允许使用 std::smart_ptr 但是我可以自己实现它并进行我想要的任何更改

这就是我所做的

#ifndef SMART_PTR_H_
#define SMART_PTR_H_

template<class T>
class smart_ptr {
    T* data;
public: typedef T element_type;
    explicit smart_ptr(T* ptr = NULL)
   : data(ptr) {}
    ~smart_ptr() {  delete data;    }
    T& operator*() const {  return *data; }
    smart_ptr& operator=(smart_ptr<T>&);
    };
template<class T>
smart_ptr<T>& smart_ptr<T>::operator=(smart_ptr<T>& ptr)
{
    delete this->data;
    T* new_data = new T(*ptr);
    this->data =new_data;
    return *this;
}
#endif

所以我的问题是,对于这样的代码

template <class T>
SortedList<T>::SortedList(const SortedList<T>& list):
  data(new smart_ptr<T>[list.max_size]),size(list.size),max_size(list.max_size)
 {
     for (int i = 0; i < size; i++)
     {
        data[i]=list.data[i];// use of operator= of smart_ptr
     }
 }

所以如果 new 抛出 std::bad_alloc 会有内存分配还是 smart_ptr 的析构函数会处理一切?

解决方法

所以如果一个新抛出的 std::bad_alloc 是否会有内存分配

如果 new 抛出,那么 new 将不会分配内存。但是,构造函数有可能进行了自己的分配,如果构造函数抛出异常,则实现不佳的构造函数可能会泄漏这些分配。

你有一个比单纯的内存泄漏更糟糕的错误:

delete this->data;
T* new_data = new T(*ptr);

如果 new 抛出,那么 this->data 将留下一个无效的指针。在析构函数中,该无效指针将被删除,程序的行为未定义。

这意味着我应该在 new 之后删除?

那会好很多,但如果析构函数抛出异常,它仍然有可能发生内存泄漏。

您可能应该暂时将任一智能指针的所有权转移到第三个本地智能指针。


但问题是如果 new 抛出了所有在 for 循环中成功的 new 会发生什么?

SortedList<T>::SortedList(const SortedList<T>& list):
    data(new smart_ptr<T>[list.max_size])

new[] 数组归 SortedList::data 所有。如果这是一个智能指针,那么应该在其析构函数中处理它。如果是裸指针,那么指向的数组以及数组内的智能指针都会泄漏。

请注意,由于您分配了一个数组,因此显示的 smart_ptr::~smart_ptr 不会执行正确的操作,因为它不使用 delete[]

实际上 SortedList::~SortedList 确实删除了 [] 数据,这样就够了吗?

没有。如果 SortedList 的构造函数抛出异常,则不会调用其析构函数。