C++模板代码导致在显然未正确分配的对象上调用删除错误

C++ template code resulting in error with delete being called on an object that apparently wasn't properly allocated

本文关键字:分配 对象 错误 删除 调用 代码 C++      更新时间:2023-10-16

我正在自学c++模板。我写了下面的代码,我得到了一个奇怪的错误,关于一个未分配的指针被释放。我猜测,当我请求此类的<int>类型时,类模板构造函数中的某些东西实际上并没有在int上调用new。该代码由CodeRunner for mac自动编译和运行,我将其设置为使用clang++编译器处理c++文件。

#include <vector>
#include <iostream>
template <typename T>
class HeapVal
{
    public:
        HeapVal(T val) {ptr = new T(val);}
        ~HeapVal() {delete ptr;}
        T get() {return *ptr;}
    private:
        T* ptr;
};
int main(){
  std::vector< ::HeapVal<int> > vec;
  for(int i = 0; i < 1000; ++i){
    ::HeapVal<int> h(i);
    vec.push_back(h);
  }
  for(int i = 0; i < 1000; ++i){
    std::cout << vec[i].get() << std::endl;
  }
  return( 0 );
}

该代码在编译或执行过程中会导致以下错误(在我看来,这类似于运行时类型的错误)。

Untitled(30214) malloc: *** error for object 0x7f82f24007c0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Run Command: line 1: 30214 Abort trap: 6           ./"$2" "${@:3}"

您缺少HeapVal的复制构造函数和赋值运算符。这意味着你最终会多次尝试delete同一内存,因为你有多个指向它的指针——这就是导致崩溃的原因。

试试这样的东西:

template <typename T>
class HeapVal
{
public:
    explicit HeapVal(T val)
    :   ptr(new T(val))
    {}
    ~HeapVal()
    {
        delete ptr;
    }
    HeapVal(const HeapVal& rhs)
    :   ptr(new T(*rhs.ptr))
    {}
    HeapVal& operator=(const HeapVal& rhs)
    {
        HeapVal(rhs).swap(*this);
        return *this;
    }
    T get() const
    {
        return *ptr;
    }
private:
    T* ptr;
    void swap(HeapVal& rhs)
    {
        std::swap(ptr, rhs.ptr);
    }
};

任何时候复制(或分配)HeapVal,都会得到两个HeapVal对象,它们都包含指向同一位置的指针。当第一个被销毁时,它将删除指向的对象。当第二个对象被销毁时,它将再次尝试删除同一个对象,从而导致未定义的行为。

在您的情况下,运行时库检测到并报告了问题,这是非常幸运的。

在谷歌上搜索"三大C++定律"或类似的东西应该会引发很多关于这个主题的讨论。

问题是,当你推送HeapVal对象时,你最终会对ptr进行浅层复制,因此这很容易被双重删除。

您需要重写默认的复制构造函数和赋值运算符,或者可以使用智能指针而不是原始ptr。Boost::shared_ptr在你的情况下可能有些过头了,但它是值得学习的。