Visual Studio 2010 C++运行时错误
我在 Visual Studio 2010 C++ 编译器中遇到了奇怪的行为。 以下代码编译但执行后抛出“调试断言失败” 信息:
“_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)”
在GCC下编译并顺利运行。是我的错吗?
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class Foo {
vector<int*> coll;
public:
void add(int* item) {
coll.push_back(item);
}
~Foo() {
for (uint i = 0; i < coll.size(); ++i) {
delete coll[i];
coll[i] = NULL;
}
}
};
int main()
{
Foo foo;
foo.add(new int(4));
Foo bar = foo;
return 0;
}
I came across strange behavior in Visual Studio 2010 C++ compiler.
Following code compiles but throws "Debug assertion failed" after execution with
message:
"_BLOCK_TYPE_IS_VALID(pHead->nBlockUse)"
Compiles and runs smoothly under GCC. Is it my fault?
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class Foo {
vector<int*> coll;
public:
void add(int* item) {
coll.push_back(item);
}
~Foo() {
for (uint i = 0; i < coll.size(); ++i) {
delete coll[i];
coll[i] = NULL;
}
}
};
int main()
{
Foo foo;
foo.add(new int(4));
Foo bar = foo;
return 0;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
您没有实现复制构造函数和复制赋值运算符(请参阅三规则)。这会导致向量中指针的浅拷贝,从而导致双重删除和断言。编辑:双重删除是未定义的行为,因此 VS 和 gcc 在这里都是正确的,他们可以做任何他们想做的事情。
通常,当您实现具有重要行为的析构函数时,您还需要编写或禁用复制构造和复制分配。
但是,在您的情况下,您真的需要通过指针存储项目吗?如果没有,只需按值存储它们即可解决问题。否则,如果您确实需要指针,请使用
shared_ptr
(来自您的编译器或 boost)而不是原始指针,这样您就无需编写自己的析构函数/复制方法。编辑:关于您的接口的进一步说明:像这样转移传入指针的所有权的接口可能会导致使用您的类的人感到困惑。如果有人传入了一个未在堆上分配的 int 的地址,那么你的析构函数仍然会失败。更好的方法是如果可能的话按值接受,或者克隆传入的项目,在
add
函数中自己调用new
。You didn't implement a copy constructor and copy assignment operator (see rule of three). This results in a shallow copy of the pointers in your vector, causing a double delete and the assertion. EDIT: Double delete is undefined behavior so both VS and gcc are correct here, they're allowed to do whatever they want.
Typically when you implement a destructor with non-trivial behavior you'll also need to write or disable copy construction and copy assignment.
However in your case do you really need to store the items by pointer? If not, just store them by value and that would fix the problem. Otherwise if you do need pointers use
shared_ptr
(from your compiler or boost) instead of raw pointers to save you from needing to write your own destructor/copy methods.EDIT: A further note about your interface: Interfaces like this that transfer ownership of passed in pointers can cause confusion by people using your class. If someone passed in the address of an int not allocated on the heap then your destructor will still fail. Better is to either accept by value if possible, or clone the passed in item making your own call to
new
in theadd
function.您删除了 item 两次,因为该行
调用了默认的复制构造函数,它复制了 itempointer,而不是分配和复制数据。
You're deleting item twice, because the line
Invokes the default copy constructor, which duplicates the itempointer, rather than allocating and copying the data.
问题是
bar
和foo
成员的向量元素是相同的。当 foo 超出范围时,它的析构函数被调用,该函数会释放指针,使bar
向量元素悬空。bar
析构函数尝试释放它的向量元素它悬空并导致运行时错误。您应该编写一个复制构造函数。编辑1:查看此线程以了解三法则
The problem is both the
bar
andfoo
member's vector element is same. Whenfoo
goes out of scope it's destructor is called which deallocates the pointer leaving thebar
vector element dangling.bar
destructor tries to deallocate it's vector element which was left dangling and is causing you the runtime error. You should write a copy constructor.Edit 1: Look at this thread to know about Rule of three
这里更简单的解决方案是首先不使用
int*
。一般来说,尽量避免
new
。如果不能,请使用智能管理器(例如 std::unique_ptr)来为您处理内存清理。
无论如何,如果您手动调用
delete
,您就做错了。 注意:不调用delete
而让内存泄漏也是错误的The simpler solution here is not to use
int*
in the first place.In general, try to avoid
new
.If you cannot, use a smart manager (like
std::unique_ptr
) to handle the memory clean-up for you.In any case, if you're calling
delete
manually, you're doing it wrong. Note: not callingdelete
and letting the memory leak is wrong too