So I have the following class method (will probably add more if requested):
EDIT 1:
Here is where paObject gets initialized and how it remains until it reaches setCapacity(int c)
template <Object>
ArrayClass<Object>::ArrayClass()
{
_size = 0; //default in case allocation fails
paObject = new Object[ARRAY_CLASS_DEFAULT_SIZE];
if (paObject == NULL)
throw Exception();
_size = ARRAY_CLASS_DEFAULT_SIZE;
}
It may be important to note that my class Vector extends (or whatever it is in c++) ArrayClass: class MyVector: virtual public ArrayClass<Object>{} and then later on in
template <class Object>
MyVector<Object>::MyVector() : ArrayClass<Object>()
{
_currSize = 0;
_incFactor = 5;
}
it forces to call the ArrayClass constructor.
template <Object >
void MyVector<Object>::setCapacity(int c)
{
int len = _currSize;
if (len > c) len = c;
Object* paNew = new Object[c];
if (paNew == NULL) throw Exception();
for (int i = 0; i < len; i++)
paNew[i] = paObject[i];
if (paObject != NULL)
delete[] paObject;
paObject = paNew;
_size = c;
if (_currSize > len)
_currSize = len;
}
When the error happens, the value of c is 6 and the value of _currSize (a class private int variable) is 1. It is also remarkable to remark that paObject is a class pointer of type Object (which is a template... etc. etc.) initialized with an array of Objects of size 1 by the time the error happens (Object* paObject = new Object[1]).
Everything executes fine up until it reaches the line delete[] paObject; at which point it gives me a Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) error.
I seriously don't understand what is wrong.
Help would be appreciated.
This error occurs when you have a heap problem.
Something like:
int *a = new char[1];
a[500] = 0;
then later, on totally unrelated object you will get an error on delete or new.
You haven't shown us where paObject is declared ... or where it's (re)initialized ...
... but that's almost certainly the problem.
If you haven't initialized it to NULL, it might contain random garbage. In which case it won't evaluate to NULL, and Bad Things will happen.
Similarly, if don't explicitly reset it to NULL, then Bad Things will also happen.
Of course, we don't even know if paObject is an array (allocated with "new []") ... because you haven't shown us.
BOTTOM LINE:
1) Make sure paObject is initialized before you use it, and correctly initialized before you re-use it.
2) If you treat it as an array object, make sure it's initialized as an array object
3) You also need to be careful about the differences between "Object", "Object references" (&Object or Object *), arrays of Objects. In particular, you need to consider when you're passing a reference to an existing object, or when you're (perhaps unintentially) creating a new object.
These links should help:
http://cplus.about.com/od/learning1/ss/constructors.htm
http://www.tutorialspoint.com/cplusplus/cpp_copy_constructor.htm
==================================================================
ADDENDUM:
It sounds like the error Expression: _BLOCK_TYPE_IS_VALID(pHead->nBlockUse) is occurring because you're overwriting your array.
Object* paObject = new Object[1] // This is really easy to overwrite!
I don't see where in the code you're writing to paObject (or writing to some alias of paObject), but I'm almost certain that's the problem.
IMHO...
Related
I am trying to change a class member's value that created in heap with address and getting the error down below.
class class2 {
private:
string String = "x";
public:
string function() {
return String;
}
};
class class1 {
public:
string String;
class2* i;
void address(class2* x) {
x = new class2();
i = x;
}
void function(string x) {
String = x;
}
};
int main() {
int len;
cin>>len;
class1 **Class1 = new class1*[len];
for(int i = 0; i < len; i++) {
Class1[i] = new class1[i];
}
Class1[0]->address(Class1[0]->i);
Class1[0]->function(Class1[0]->i->function());
cout<<Class1[0]->String;
}
Exception thrown at 0x0F4D514F (vcruntime140d.dll) in Project70.exe:
0xC0000005: Access violation writing location 0xDDDDDDDD.
This call of the new operator
Class1[i] = new class1[i];
is invalid. You mean
Class1[i] = new class1;
Pay attention to that this member function
void address(class2* x) {
x = new class2();
i = x;
}
does not make great sense because the passed argument to the function is not used.
Okay, lets take this step by step, to illustrate what's going wrong. It's pretty clear you're learning C++, so I'll try to write to that audience.
int len;
cin>>len;
1) read in a length from standard in. No serious problems yet. You could check to be sure it's not negative or zero, but we'll let that slide for now. We'll pretend that "len = 3", and move on from here.
class1 **Class1 = new class1*[len];
2) you create a pointer to pointer to class1 called Class1. I can't say that I like your naming scheme, but lets work passed that too, and set Class1 to an array of pointers to class1. So far so good. If len were zero or negative, you can imagine the problems you might have. Note that none of the memory for those pointers has been initialized, just set aside to hold things you put in it later.
for(int i = 0; i < len; i++) {
Class1[i] = new class1[i];
}
3) This will create some new instances of class1, and point Class1[I] at them. With len = 3, this will create a weird grid of allocations. The first array will be of length ZERO, the second of length 1, and the third of length 2. ZERO length arrays are bad.
So with that zero length array ready to blow up like a land mine when we step on it, lets go for a walk!
Class1[0]->address(Class1[0]->i);
First of all, this is pretty misleading. It would be better written as Class1[0][0].address(Class1[0][0].i); Second, passing 'i' into a function whose sole purpose is to write to a member variable that happens to be that parameter you just passed in is pointless. Just write to the member variable.
And third: Boom. We just stepped on the zero-length-array-land-mine. But all is not lost.
You can salvage this with a relatively small number of changes.
Class1[i] = new Class1[len]; will give you a grid of allocations (3, 3, 3) rather than a triangle (0, 1, 2).
for every call to new you need a call to delete, preferably in that class's destructor. Destructors are awesome. You call new in address (remove it's parameter, you don't need it), so somewhere need to call delete. Also, you should set i to nullptr in the constructor so you don't accidentally try to delete something invalid.
for every call to new[] you need a call to delete[]. You looped through an array calling new[], so you need to loop through that array calling delete[] to clean it up.
Variable names. I'm guessing English isn't your first language, and you're learning C++ too, so I understand. However, your function and variable names are meaningless at best (class1, class2, i, x), and misleading at worst (address doesn't take anything's address, it creates something). Even with not much to go on, you could at least use names like "InnerClass", "OuterClass", "message", "createInner", "innerPtr"... and they wouldn't be nearly as difficult to figure out.
<RANT MODE>
What are we, mathematicians?! We have all the space we need to describe things, so be descriptive. Mathematicians used to be confined to a blackboard, and had to write everything by hand, so some pressure to use (overly) concise (impossible for outsiders to comprehend) notations was understandable... but now? They don't eve have that excuse. And I'm looking at you too Physicists! Yeah you, in the lab coat!
</RANT MODE>
And learn to touch type. Programmers end up typing a LOT, and looking from screen to keyboard and back kills your typing speed.
So, I have an array of a class called "Customer"
Customer** customersarray[] = new Customer*[customer];
I'm receiving int customer with cin.
anyways, in customer.cpp, there is a method called void deactivate().
which goes like this:
void Custmoer::deactivate()
{
if (this != NULL)
remove this;
//this = NULL; I want to do this but it doesn't work.
}
and the purpose of this is to remove it from customer array when satisfies a certain condition. So for example,
for (int i = customer - 1; i >= 0; i--)
{
if (customersarray[i]->getAngerLevel() == 5) {
customersarray[i]->deactivate();
}
for (int z = i; i < customer - 1; i++) {
*(customersarray + z) = *(customersarray + z + 1);
}
customer--;
}
so my first questions are:
why does this = NULL not work?
is there a simpler way to remove something from pointer array when a condition is satisfied? (for example, remove all customers that has anger level of 5.)
Your mistake is thinking that you can remove something from a Customer* array by some magic inside the Customer class, but that's not true. Just remove a customer from the customer array where ever the customer array is. For instance using remove_if
#include <algorithm>
Customer** customersarray = new Customer*[customer];
...
customer = std::remove_if(customersarray, customersarray + customer,
[](Customer* c) { return c->anger() == 5; }) - customersarray;
This updates the customer variable to be the new size of the array, but doesn't free or reallocate any memory. Since you are using dynamic arrays and pointers you are responsible for that.
Which is why you should really not be using pointers or arrays, but using vectors instead.
std::vector<Customer> customerVector;
Life will be so much simpler.
Type of "this" is a constant pointer which means you cant change where it points
Your function can return a boolean and if its true just set your pointer to null
You'll be much better off using a std::vector, all memory memory management gets much safer. You cannot modify the this pointer, but that would be meaningless anyway:
It is a local variable, so any other pointer outside would not be changed, not even the one you called the function on (x->f(): the value of x is copied into this).
It contains the address of the current object - the current object is at a specific memory location and cannot be moved away from (not to be mixed up with 'moving' in the context of move semantics!).
You can, however, delete the current object (but I don't say you should!!!):
class Customer
{
static std::vector<Customer*> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
delete this;
}
}
Might look strange, but is legal. But it is dangerous as well. You need to be absolutely sure that you do not use the this pointer or any other poiner to the current object any more afterwards (accessing non-static members, calling non-static functions, etc), it would be undefined behaviour!
x->commitSuicide();
x->someFunction(); // invalid, undefined behaviour!!! (x is not alive any more)
Similar scenario:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
void commitSuicide()
{
auto i = customers.find(this);
if(i != customers.end())
{
customers.erase(i); // even now, this is deleted!!! (smart pointer!)
this->someFunction(); // UNDEFINED BEHAVIOUR!
}
}
}
If handling it correctly, it works, sure. Your scenario might allow a much safer pattern, though:
class Customer
{
static std::vector<std::unique_ptr<Customer>> customers;
public:
Customer()
{
customers->push_back(this);
};
~Customer()
{
auto i = customers.find(this);
if(i != customers.end())
customers.erase(i);
}
}
There are numerous variations possible (some including smart pointers); which one is most appropriate depends on the use case, though...
First of all, attending to RAII idiom, you are trying to delete an object before using its destructor ~Customer(). You should try to improve the design of your Customer class through a smart use of constructor and destructor:
Customer() {// initialize resources}
~Customer() {// 'delete' resources previously created with 'new'}
void deactivate() {// other internal operations to be done before removing a customer}
Then, your constructor Customer() would initialize your internal class members and the destructor ~Customer() would release them if necessary, avoiding memory leaks.
The other question is, why do you not use another type of Standard Container as std::list<Customer>? It supports constant time removal of elements at any position:
std::list<Customer> customers
...
customers.remove_if([](Customer foo) { return foo.getAngerLevel() == 5; });
If you only expect to erase Customer instances once during the lifetime of the program the idea of using a std::vector<Customer> is also correct.
Lets say i have a class like this:
class LolClass {
LPWSTR* stuff;
LolClass::LolClass(LPWCHAR lols) {
stuff = new LPWSTR[100];
for (int i = 0; i < 100; i++) {
stuff[i] = new wchar_t[wcslen(lols)+1];
wcsncpy(stuffs[i], lols, wcslen(lols)+1);
}
}
LolClass::~LolClass() {
delete[] stuff;
}
}
so if i call
LolClass* veryfunny = new LolClass(L"lol!");
it would make me 100 lol's, problem is when i call
delete veryfunny;
it deletes the pointer array but not the individual wchar_t's, if i try and loop through the wchar_t's and delete them then i just crash and i dont know what to do since i know for fact that they are still there even after i delete veryfunny (i checked by passing one of the pointers outside the class)
Thanks!
If you call
LolClass* veryfunny = new LolClass(L"lol!");
then you will eventually need to call:
delete veryfunny;
But for arrays, you need delete[]: stuff[i] = new wchar_t[n]; delete [] stuff[i];
In your code, you need to first loop over stuff and delete[] the elements, and then delete[] the array stuff itself.
Or just use a std::vector<std::wstring>.
Update: From what I understand, you're not actually worried about deleting *veryfunny, but rather about how to write a correct destructor for LolClass. Note that the destructor also gets invoked for global and automatic objects, e.g. { LolClass x(L"hello"); } /* boom */, so it doesn't really matter how you instantiate an object for LolClass. You have to get the class right in any case.
David Schwartz wins after all, the wchar's didnt let themselves be deleted because they werent null terminated
As someone who never dealt with freeing memory and so on, I got the task to create a dynamic array of struct and create functions to add or delete array elements. When deleting I have to free the memory which is no longer necessary.
when deleting the 2nd element of an array of the size of 3, I move the 3rd element to the 2nd position and then delete the last one. When deleting the last one, I always get an error... Is there anyone who can find an solution for me?
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend* friendList = new myFriend[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = *tempFriend;
friendList[1] = *tempFriend2;
friendList[2] = *tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete &(friendList[2]); //and delete 3rd element to free memory
}
Why did you create temporary variables? They're not even needed.
If you use std::vector and std::string, the problem you're facing will disappear automatically:
std::vector<myFriend> friendList(10);
friendList[0]->number=1;
friendList[0]->name = "ABC";
friendList[1]->number=2;
friendList[1]->name = "XYZ";
friendList[2]->number=3;
friendList[2]->name = "123";
To make it work, you should redefine your struct as:
struct myFriend {
int number;
std::string name;
std::vector<std::string> hobbys;
};
If you're asked to work with raw pointers, then you should be doing something like this:
struct Friend
{
int number;
char* name;
};
Friend * friends = new Friend[3];
friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");
//similarly for other : friends[1] and friends[2]
//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;
delete [] friends; //and finally this!
And if you do any of the following, it would be wrong, and would invoke undefined behavior:
delete friends[2]; //wrong
delete &(friends[2]); //wrong
It is impossible to delete a subset from array allocated by new []
myFriend* friendList = new myFriend[10];
You have a single whole array
+------------------------------------------------------------------+
| friendList[0] | friendList[1] | ..... | friendList[9] |
+------------------------------------------------------------------+
You can not delete &(friendList[2]).
You get from C++ whole array of 10 elements.
This array starts from friendList (or &(friendList[0])).
operator delete with pointer to the address returned by new (i.e. friendList) is valid
only.
Two things I noticed. (1) You are apparently supposed to "create functions to add or delete elements" but you haven't done that, you have only created one function. (2) You are making your work harder than it needs to be by using a struct that also needs to manage memory. I suggest you use a simpler struct.
Your assignment is, in effect, to make a simple 'vector' class, so I suggest that you do that. Start with a struct that is empty. If the teacher requires you to use the myFriend struct as written, you can add that in after you finish making your vector like functions. I'm going to assume that you aren't allowed to make a class yet because most instructors make the mistake of leaving that until last.
struct MyStruct {
int value; // start with just one value here. Dealing with pointers is more advanced.
};
MyStruct* array;
int size;
int capacity;
void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'
// I leave the functions for you to implement, it's your homework after all, but I give some clues below.
void addMyStruct(MyStruct& value) {
// First check that there is enough capacity in your array to hold the new value.
// If not, then make a bigger array, and copy all the contents of the old array to the new one.
// (The first time through, you will also have to create the array.)
// Next assign the new value to array[size]; and increment size
}
void removeMyStructAtPosition(int position) {
// If the position is at end (size - 1,) then simply decrement size.
// Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
// from position to the end of the array.
}
int main() {
// test your new class here.
// don't forget to delete or delete [] any memory that you newed.
}
The array size is fixed at 10, so you don't need to delete any elements from it. But you do need to delete the name and hobbys elements of friendList[1] (and before you overwrite it). There are two problems here:
You are setting friendList[0]->name = "ABC"; Here, "ABC" is a constant zero-terminated string somewhere in memory. You are not allowed to delete it. So you have to make a copy.
You want to delete hobby[i] whenever it was assigned. But in your code, you can't tell whether it was assigned. So you have to set every element to 0 in the constructor, so that you will later know which elements to delete.
The proper place to delete these elements is in myFriends's destructor.
It seems the point of the question is to manage a dynamic array. The main problem is that he is using an array of friendList. Use an array of pointers to friendList:
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend** friendList = new myFriend*[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = tempFriend;
friendList[1] = tempFriend2;
friendList[2] = tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete friendList[2]; //and delete 3rd element to free memory
}
But everybody else is right -- there are major issues around memory allocation for both 'hobbys' and for 'name' that you need to sort out separately.
To do your homework I'd suggest to learn much more about pointers, new/delete operators, new[]/delete[] operators (not to be confused with new/delete operators) and objects creation/copying/constructors/destructors. It is basic C++ features and your task is all about this.
To point some directions:
1) When you dynamically allocate the object like this
MyType* p = new MyType;
or
MyType* p = new MyType(constructor_parameters);
you get the pointer p to the created object (new allocates memory for a single object of type MyType and calls the constructor of that object).
After your work with that object is finished you have to call
delete p;
delete calls the destructor of the object and then frees memory. If you don't call delete your memory is leaked. If you call it more than once the behavior is undefined (likely heap corruption that may lead to program crash - sometimes at very strange moment).
2) When you dynamically allocate array like this
MyType* p = new MyType[n];
you get the pointer p to the array of n created object located sequentially in memory (new[] allocates single block of memory for n objects of type MyType and calls default constructors for every object).
You cannot change the number of elements in this dynamic array. You can only delete it.
After your work with that array is finished you have to call
delete[] p; // not "delete p;"
delete[] calls the destructor of every object in the array and then frees memory. If you don't call delete[] your memory is leaked. If you call it more than once the behavior is undefined (likely program crash). If you call delete instead of delete[] the behavior is undefined (likely destructor called only for the first object and then attempt to free memory block - but could be anything).
3) When you assign the struct/class then operator= is called. If you have no operator= explicitly defined for your struct/class then implicit operator= is generated (it performs assignment of every non-static member of your struct/class).
_transaction is a private member variable of my class, declared as:
public:
typedef stdext::hash_map<wchar_t*, MyClass*, ltstr> transaction_hash_map;
private:
transaction_hash_map _transactions;
During cleanup I am trying to iterate through this list and free up any objects still unfreed. However I am getting an AV on the for line here:
for (transaction_hash_map::const_iterator it = _transactions.begin(); it != _transactions.end(); it++)
{
MyClass* item = (MyClass*)it->second;
if (item != NULL)
{
item->End();
delete item;
}
}
Re: What is ltstr?
private:
struct ltstr
{
enum
{
bucket_size = 8,
min_buckets = 16
};
bool operator()(wchar_t* s1, wchar_t* s2) const
{
return wcscmp( s1, s2 ) < 0;
}
size_t operator()(wchar_t *s1) const
{
size_t h = 0;
wchar_t *p = const_cast<wchar_t*>(s1);
wchar_t zero = L'\0';
while ( *p != zero ) h = 31 * h + (*p++);
return h;
}
};
The stack shows it inside the begin() method. Any ideas?
One possible thing I can think of is that your class has already been deleted elsewhere before you try to iterate through the hash_map, and thus begin() will be operating on garbage. Worth a check...
Also - how are your wchar_t*'s getting allocated/freed? The code you've shown doesn't appear to be dealing with those. I'm not sure how that would cause trouble in your loop, but it's worth thinking about.
One minor thing - you shouldn't need the (MyClass*) cast. The hash_map's values should be of that type anyway, so it's nicer to let the compiler enforce type checks than to possibly bypass them with an explicit cast. That shouldn't be making any difference here though.
As I understand you're checking your pointer against NULL for the "remaining" items that might have not been deleted yet. But for the items you delete before your cleanup stage, do you set the pointer to NULL?
Notice that when you delete an object the pointer is not automatically set to NULL. So if you're not doing that you're trying to delete the same object twice (because your if statement will always be true), what could cause an access violation.
The code below is an example that causes a double deletion. It can be fixed if you uncomment the line that sets the pointer to NULL.
#include <cstddef>
struct Item {};
int main()
{
Item * p = new Item();
delete p;
//If you don't make the pointer null...
//p = NULL;
if (p != NULL)
//You delete the object twice.
delete p;
}
EDIT: I see you're getting the error exactly on the for line. So I'm wondering...
Apparently you have a MyClass that contains a _transactions member, which is a hash table with MyClass pointers as the data type. If the clean up code is performed inside a member function of MyClass, is it possible that you're deleting (for some reason) the MyClass instance that owns the _transactions you're iterating?
In this case you could get an error at it++ statement inside the for since the this object no longer exists. (Naturally, the error could be somewhere else too, like on the delete itself.)
Make sure to call _transactions.clear() after the for loop.