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;
}
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 the add
function.
You're deleting item twice, because the line
Foo bar = foo;
Invokes the default copy constructor, which duplicates the itempointer, rather than allocating and copying the data.
The problem is both the bar
and foo
member's vector element is same. When foo
goes out of scope it's destructor is called which deallocates the pointer leaving the bar
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.
Foo bar = foo; // Invokes default copy constructor.
Edit 1: Look at this thread to know about Rule of three
The simpler solution here is not to use int*
in the first place.
#include <iostream>
#include <vector>
using namespace std;
typedef unsigned int uint;
class Foo {
vector<int> coll; // remove *
public:
void add(int item) { // remove *
coll.push_back(item);
}
// remove ~Foo
};
int main()
{
Foo foo;
foo.add(4); // remove `new` call
Foo bar = foo;
return 0;
}
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 calling delete
and letting the memory leak is wrong too
精彩评论