I have a problem.
The compiler keeps warning me for invalid use of the constructor.
All i wanted to do is to create a new course in the class. whats wrong?
int StArray::addCS_Course(int id, int CourseNum, char* CourseName,int HwNum, float HwWeigh, bool Takef, char* BookName){
int i;
CS_Course* course;
if ((CourseNum<0)||(HwNum<0)||(HwWeigh<0)||(HwWeigh>1))
return 0;
for (i=0;i<StudentNum_;i++){
if (Arr_[i]->getID()==id) {
course=(CS_Course*)malloc(sizeof(CS_Course*));
if (course==NULL) {
fprintf(stderr,"Malloc failed\n");
exit(0);
}
course->CS_Course::CS_Course(CourseNum,CourseName,HwNum,HwWeigh,Takef, BookName);
if (Arr_[i]->addCS_Course(course)==1)
return 1;
else
{
free(course);
return 0;
}
}
}
return 0;
}
To create a new object in C++, you don't do this:
course = (CS_Course*) malloc(...);
course->CS_Course::CS_Course(...);
you do this:
course = new CS_Course(...);
That code looks after both allocating memory and calling the constructor.
You then delete your object with delete course; rather than free(course);
(But as juanchopanza points out in the comments, it's considered bad form to create objects on the heap in C style like this - you should prefer to use standard library containers and avoid the use of new. That's a whole nother discussion - you might want to read a tutorial on modern C++.)
Edit by #RemyLebeau: If you need to construct an object in existing memory, use placement new instead:
buffer = malloc(...);
course = new (buffer) CS_Course(...);
But then you have to call the destructor manually:
course->~CS_Course();
free(buffer);
malloc(sizeof(CS_Course*)) allocates enough space for a pointer to a CS_Course, not a CS_Course itself. If malloc were the right way to dynamically allocate memory for an object, you would need to call it like this:
malloc(sizeof(CS_Course));
However, malloc isn't the right way to do this; in C++, you use new to dynamically allocate memory for objects:
course = new CS_Course; //Use the default constructor
or
//Use constructor with 2 parameters
course = new CS_Course(constructor_param1, constructor_param2);
Of course, if you don't need a pointer, you can (and should) create a CS_Course object like this (generally referred to as allocating on the stack):
CS_Course course; //default constructor
//constructor with 2 parameters
CS_Course course2(constructor_param1, constructor_param2);
Related
I am trying to print out value 123456, but it gives me the garbage value. How can I fix it? And Can you please explain why it gives the wrong value?
#include <stdio.h>
#include <stdlib.h>
struct MyInfo
{
private:
int private_key = 123456;
public:
int setkey(int value)
{
private_key = value;
}
int GetScore()
{
return private_key;
}
};
void main()
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo));
printf("%d\n", pMyInfo->GetScore());
free(pMyInfo);
}
Don't use malloc/free but rather pMyInfo = new MyInfo() and delete pMyInfo. Only new will call the constructor which initializes the value; only delete will call the destructor.
Regarding the comment, what is meant is, you can also have it on the stack, i.e. MyInfo pMyInfo;, i.e. not a pointer. That will automatically call the constructor and when it goes out of scope, the destructor.
int private_key = 123456;
This really is just a camouflaged constructor initialization which means it's the same as:
MyInfo() : private_key(123456) {}
Since malloc and friends are inherited from C and C has no classes (and thus no special member functions) whatsoever malloc and friends won't call these necessary special member functions to set up your object. The C++ equivalent new does however which is why you should always use new over malloc and delete over free.
But wait, there's more...
Actually, you shouldn't ever use new either, there are always better alternatives than using raw dynamic allocation. If you really need dynamic memory allocation then use std::unique_ptr or for multiple objects std::vector but most of the time you don't even need these ( there are tons of posts on here that explain when dynamic allocation is a must, for all the other cases just use storage with automatic lifetime) all you need in this case is a local object:
MyInfo myInfo;
printf("%d\n", myInfo.GetScore());
See how your code just got shorter, easier to maintain and cleaner to achieve the same?
When you declare a pointer of type MyInfo, it does not mean that the object it points to will actually be your struct, it just assumes it will be.
When you do malloc(sizeof(MyInfo)), you simply allocate memory of the size which your struct might take, it does not create an object. Hence, when you try to do GetScore(), it accesses memory location which it assumes contains your private_key, but instead it simply contains garbage.
Don't mix C and C++
You should avoid malloc/alloc etc in C++ and opt for new operator if you want to work with dynamically allocated objects.
Add a constructor to initialize the value
private;
int private_key;
public:
MyInfo () {
private_key = 123456;
}
And implement the main like
// without pointer
void main () {
MyInfo myinfo;
printf("%d\n", myinfo.GetScore());
}
// with pointer
void main () {
MyInfo *myinfo = new MyInfo();
printf("%d\n", myinfo->GetScore());
}
Just for reference, it is possible to initialize an object in raw storage, but it would be overkill and rather stupid for this use case. As malloc only allocate raw memory and does not construct an object, you could use a placement new to build the object in a second time:
int main() // I can't stand void main
{
MyInfo* pMyInfo;
pMyInfo = (MyInfo*)malloc(sizeof(MyInfo)); // only allocate raw memory
new((void *) pMyInfo) MyInfo; // construct the object
std::cout << pMyInfo->GetScore() << std::endl; // no reason for C printf here
pMyInfo->~MyInfo(); // placement new requires explicit destructor call if not trivial
free(pMyInfo);
return 0;
}
DO NOT DO THAT for such a simple case. Placement new should only be used in very special cases where the allocation is not trivial, for example when you use share memory. But here the correct way is to simply use an automatic object:
int main() // I can't stand void main
{
MyInfo pMyInfo;
std::cout << pMyInfo.GetScore() << std::endl;
return 0;
}
I'm just trying this out of curiosity. I have a struct with a constructor and a copy constructor and trying to initialize the struct using the copy constructor in the main, while at the same time within the main, implementing memory allocation to the pointer to a struct. Copy construct initialization works alright, but when I try to free it before the main return, it causes an assertion error in the heap.
#include <stdio.h>
#include <malloc.h>
typedef struct tagInfo
{
int iX;
int iY;
tagInfo() {};
tagInfo(int x, int y)
: iX(x), iY(y) {};
~tagInfo() {};
}INFO;
int main (void)
{
INFO* pInfo = (INFO*)malloc(sizeof(INFO));
pInfo = &INFO(10, 10);
free(pInfo);
return 0;
}
How can I safely free the above pointer without causing assertion errors?
malloc and free should not be used in C++, as they do not deal with construction/destruction of objects.
In modern C++ you should use std::unique_ptr if you want to model unique ownership, or std::shared_ptr if you want to model shared ownership - these are called "smart pointers" and provide a safe way of managing dynamic memory that automatically deals with deallocation/destruction. Example:
int main (void)
{
auto pInfo = std::make_unique<INFO>(10, 10);
return 0;
}
If you really want to go down the road of manual memory management, you must use new (for allocation+construction) and delete (for deallocation+destruction). Example:
int main (void)
{
INFO* pInfo = new INFO(10, 10);
delete pInfo;
return 0;
}
I think the basic misunderstanding is that a copy constructor does not copy the contents of one object into an (already existing) other object of the same type, but rather generates a new object, which is initialized based on the contents of the object to be copied from.
In your code, you reserve memory for an object of type INFO using malloc and let pInfo point to that memory.
Next, with pInfo = &INFO(10, 10) you instantiate a new object of type INFO on the stack (not on the heap), and let pInfo point to the memory address of this object (which is on the stack!). BTW, you loose the reference to your malloc-ed memory, as pointer pInfo does not point to the malloc-ed address any more, but on the new object.
free(pInfo) is critical, as you free a memory address which has not been allocated with malloc before.
Actually, you should do the following:
INFO* pInfo = new INFO(10, 10);
...
delete pInfo;
In general, you can do that with placement new, but it is highly discouraged:
// allocate
void* pInfoMem = malloc(sizeof(INFO));
// construct
INFO* pInfo = new(pInfoMem) INFO(10, 10);
// destruct
pInfo->INFO::~INFO();
// free
free(pInfoMem);
But then you need to manually call the destructor before the freeing.
It is much easier to just do (as other answers mention):
INFO* pInfo = new INFO(10, 10);
delete pInfo;
This isn't the code I'm working on but it's the gist of what I want to do.
object *objects; int totalObjects;
void addObject(object o)
{
objects[totalObjects] = o;
totalObjects++;
}
It's giving me an access error when I try this:
Unhandled exception at 0x00e8a214 in crow.exe: 0xC0000005: Access violation writing location 0xcccccccc
Am I going to have to use 'new' and if so do I have to create a new array to copy to every time? Can I just add or take elements from the array I'm using?
Why don't you just use std::vector?
std::vector<object> objects;
void addObject(object o)
{
objects.push_back(o);
}
..or
void addObject(const object &o)
{
objects.push_back(o);
}
to remove additional copying.
When it comes to implementing your own dynamic array without std::vector, Yes. you need to allocate new memory, and copy your array to new memory block. Here's my example code with malloc and placement new.
#include <stdlib.h> // for malloc/free
#include <new> // for placement new, std::bad_alloc
object *objects = nullptr;
size_t totalObjects = 0;
void addObject(const object &o)
{
object *old_objects = objects;
size_t old_size = totalObjects;
size_t new_size = totalObjects + 1;
object *new_objects = (object *)malloc(sizeof(object) * new_size);
if (new_objects == nullptr)
throw std::bad_alloc();
size_t i;
try
{
for (i = 0; i < old_size; ++i)
{
new (&new_objects[i]) object(old_objects[i]); // placement new
}
}
catch (...)
{
// destroy new_objects if an exception occurs during creating new_objects
for (size_t j = 0; j < i; ++j)
{
new_objects[i].~object();
}
free(new_objects);
throw;
}
objects = new_objects;
free(old_objects);
}
(I haven't tested the code yet >o<)
Note that I used malloc and placement new, not new operator. It's impossible to call copy constructor of each element of the dynamic array with array-new.
However, if your object is TriviallyCopyable, you can use realloc. It can be more efficient, because realloc can just expand memory block, without copying - if the memory is enough.
..And you can select multiple lines and just press TAB in Visual Studio (..or many other editors).
You declared an object pointer, but not yet allocated the actual memory to store object objects. Your assignment statement merely tries to copy the input object o into an unallocated array member.
This is why you should use new before the assignment. The new operator asks the system to allocate some memory in the required size, then return the address of that memory and assign it to the pointer. Then, the pointer points to that newly allocated memory and the assignment (or copying) can be made.
When you finished using the array space, you should free the allocated memory using delete.
Okay, I'm going to add an answer to my own question. Let me know if this is bad etiquette. I just wanted to post some of my own code to duel with yours.
#include <vector>
std::vector<object> objects;
okay so I want to have two arrays (vectors) for the objects and double for distances so I may end up with
std::vector<double> distances;
void swap(unsigned int a, unsigned int b)
{
objects.swap_ranges(a,b);
distances.swap_ranges(a,b)
}
I'm going by the cplusplus.com reference for this function so let me know if I have it wrong. I'm going to go through it and completely redo my code.
Is there a type like the matrix that will let me hold data of different types so I don't have to invent a new object to handle each one individually?
If what you wrote is the most efficient and fast way to do this then I'll make a new class to hold both items.
thanks :)
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).
I need to insert pointers of classes (inherited from QObject) into a QList. I know that the following syntax can be used:
.h
QList<MyObject*> list;
.cpp
list.append(new MyObject("first", 1));
list.append(new MyObject("second", 2));
...
and then free memory:
if(!list.isEmpty())
{
qDeleteAll(list);
list.clear();
}
This should be valid and does not cause any memory leaks (as far as I know). However, I need to initialize objects before adding them to the collection. Can the following piece of code cause some errors like memory leaks or dangling pointers (I'll use the same way to delete pointers as above)?
MyObject *obj;
for(i = 0; i < 5; i++)
{
obj = new MyObject();
if(!obj.Init(i, map.values(i)))
{
// handle error
}
else
{
list.append(obj);
}
}
Thanks.
if you take care of "obj" (the allocated but not initialized instance) in the "// handle error" case, your code is ok.
Use QSharedPointer instead.
QList<QSharedPointer<MyObject> > list;
To free memory you only have to do
if(!list.isEmpty())
{
list.clear();
}
To append to list
list.append(QSharedPointer<MyObject>(new MyObject("first", 1)));
list.append(QSharedPointer<MyObject>(new MyObject("second", 2)));
Use RAII (Resource Allocation Is Initialization). Initialize the object in constructor directly.
Then the code would look like:
for(i = 0; i < 5; i++)
{
list.append( new MyObject( i, map.values(i)));
// In case of initialization failure, throw exception from the constructor
}
You can use QScopedPointer..
From the Qt 4.6 documentation,
The QScopedPointer class stores a pointer to a dynamically allocated object, and deletes it upon destruction.
Managing heap allocated objects manually is hard and error prone, with the common result that code leaks memory and is hard to maintain. QScopedPointer is a small utility class that heavily simplifies this by assigning stack-based memory ownership to heap allocations, more generally called resource acquisition is initialization(RAII).
Hope it helps..
Edit:
For example,
You will use,
QScopedPointer<QWidget> p(new QWidget());
instead of
QWidget *p = new QWidget();
and add the QScopedPointer into your QList without worrying about memory leak and dangling pointers.