C++模板代码导致在显然未正确分配的对象上调用删除错误
C++ template code resulting in error with delete being called on an object that apparently wasn't properly allocated
我正在自学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在你的情况下可能有些过头了,但它是值得学习的。
相关文章:
- 使用操作重载对象重新分配对象
- 静态分配对象的值初始化
- C++ 将抽象类型的动态分配对象传递给函数并存储在向量中
- 堆分配对象中的堆栈对象在 c++ 中在哪里分配?
- 在 c++ 的构造函数中分配对象向量时出错
- 动态分配对象中的字段-动态分配更好还是静态分配更好?C++
- 操作后通过运算符分配对象
- 如何捕获源自静态分配对象的构造函数的异常?
- 在C++中,当重新分配对象时,为什么构造函数在析构函数之前触发?
- 如何使用每个对象的单个构造函数参数动态分配C++对象数组?
- 将动态分配对象传递到 boost::any 构造函数中
- 混合指向已分配对象和作用域对象的指针
- C 删除指向动态分配对象的指针
- 有关动态分配对象的问题
- 类的堆分配对象是否在其作用域之后但在 C++ 中调用其析构函数之前处于活动状态
- C++ 中的黑白堆分配对象和堆栈分配对象的性能差异
- 是隐式创建的默认构造函数,负责分配对象内存
- 如何删除用于动态分配对象的智能指针
- 分配对象数组时如何初始化每个对象
- 用于堆栈分配对象的C++虚拟析构函数内联