It depends. If you want that array to simply be a part of that object, within the memory block allocated to that object, wherever that object happens to be created, then you don't need to dynamically allocate the array independently of the class.
If, however, you need to ensure that the array is on the heap, regardless of how the object is allocated, then you should dynamically allocate the array explicitly.
So everything within the object(created with "new") ends up on the heap and if I dont want the array to live longer than the object it is in, then new is only necessary for the object?
pointers (meaning dynamic memory specifically, that is pointers that need a new and delete) inside classes cause headaches, more than anything.
- you have to get memory for it. usually you will do this in the constructor if possible. if not possible because the user needs to do something first to give you a size, then you have to enforce that the user does that thing and the memory is gotten before you try to use the pointer. Doing it in the constructor means that when you new the object, it news the internal pointer for you as part of creating it.
- you have to get rid of the memory. This means an explicit destructor.
- you have to make an explicit assignment if your class has assignment operator and it has to copy the data, not the pointer.
- your copy ctor, if any, needs special attention as above
and so on. across the board you have to constantly be careful not to leak memory or accidentally copy or provide a pointer when you meant to handle the data. Pointers have a nasty habit of triggering the rule of 3 and/or rule of 5.
a vector or similar container gets rid of most of these problems, with the exception of serialize where you still need to be careful (true for both).
IIRC, the OP has stated elsewhere that they are specifically trying to learn about pointers, arrays and C-style strings, and a lot of these questions are coming from learning exercises based around those topics.
Unless I've gotten them confused with someone else...
well, if you did what I said and put the free in the destructor, then calling delete on the object will trigger the dtor which will delete the pointer's newed memory. Again, this and the above (it news for you) BOTH RELY ON CTOR AND DTOR as stated. If you don't do those as I said, then the automatic handling is NOT DONE.
so yes, if you followed the pattern I gave, then yes, it would allocate and destroy the internal pointer for you when you allocate and destroy the a pointer at the object level, but its something YOU have to put into the class to have this nice feature.
I maybe better give code for this.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
class sigh
{
char *cp;
};
sigh *x = new sigh; //cp is uninitialized. it does not have any new'ed memory.
//nothing at all happens upon delete of x.
class nicer
{
char *cp;
nicer(){cp = newchar[1000]; cp[0] = 0;}
~nicer(){delete [] cp;}
};
nicer *n = new nicer; //cp is allocated and ready to use as an empty c-string.
delete n; //cp is destroyed for you. THESE THINGS HAPPEN BECAUSE YOU CODED IT TO!
if you added the constructor to sigh and did not add the destructor, then a new and delete on x would leak memory.
class nicer
{
char *cp;
nicer(){cp = newchar[1000]; cp[0] = 0;}
~nicer(){delete [] cp;}
};
nicer *n = new nicer;
If the class object is created with "new"(nicer * n = new nicer), then why "new" to cp as well? Woudln't it be enough with "char cp[1000]", then no need for delete of specific members, just the object?
Honestly, for this, forget about heap vs. stack. Just think about automatic vs. dynamic lifetime. Heap vs. stack is an implementation detail.
Just focus on one layer at a time.
On the outer layer, all you know that you have is. nicer *n = new nicer;
What is inside nicer doesn't matter; all that matters here is that new nicer has a dynamic lifetime, and must be deleted manually.
Then, you have the inner layer. cp = newchar[1000]; This allocated an array of data with a dynamic lifetime, so it must be delete[]'d manually.
If you did char[1000] chs; it would have automatic lifetime, as far as that layer is concerned; i.e. it will be automatically removed once the thing it belongs to is removed, be that automatically or dynamically.
_________________________________________________
then why "new" to cp as well? Wouldn't it be enough with "char cp[1000]", then no need for delete of specific members, just the object?
If you use new/new[], you have to use delete/delete[]. At every layer, independently.
yes, cp can certainly be an array. And yes, it probably should be a vector, or if its meant to be a string, it should be a string. Absolutely. (fun facts, but vector or string and such are usually doing a new/delete for you internally, so its the same *pattern* that I showed you, but hidden and handled for you, saving you debugging and frustrations and code bloat).
As far as it goes, if you type the keword new, you need to somewhere have typed the keyword delete. If you use an array, vector, string, etc in your class, and do not type the word new, then you don't need the delete. And that means you may not need to write your own destructor and won't need a custom default constructor (you can have it but its no longer required to make the class work nicely). This is highly desirable: you do not want to have to write your own destructors and do all this extra stuff: it gets in the way of expressing your idea and bogs you down in unnecessary details and puts you at risk of the most frustrating classes of bugs (memory problems, whether out of bounds, access of nulls, or leaks, not to mention pointer pointing at wrong block at the wrong time).
What I was showing you, really, is how to do something that you should not ever need to do, or very, very rarely. But its good to understand it. And it was what you had asked.
That class does not follow the Rule of Zero/Three/Five. The copy constructor and assignment, and the move constructor and assignment seem to be forgotten. (All are not compulsory, but the decision has to be explicit and with sound rationale.)
If the class object is created with "new"(nicer * n = new nicer), then why "new" to cp as well?
Woudln't it be enough with "char cp[1000]", then no need for delete of specific members, just the object?
That was already discussed and the answer was: "depends"
However, "If the class object is created with new" is a problematic question. How do you know?
How do the authors of C++ Standard Library know whether std::string will be used with automatic or dynamic lifetime?
They don't. They can anticipate probable use patterns, document preferred use patterns, and somewhat restrict usage, but ultimately design of a class and use of the class are separate.
All are not compulsory, but the decision has to be explicit and with sound rationale.
rationale: its a very tiny example of what he asked about... I mentioned dealing with the rest of it several posts back as a reason to avoid pointers in classes, but its worth driving the point home as these are often overlooked in more serious code.
So my new question is: How do I create arrays even larger than 2000000000?
1) use a vector. It will handle the memory for you up to the size that you run out of hardware (which means, solid block of memory big enough for the thing).
2) if you run out of what a vector can handle, you will have to use something less efficient that can allow the memory to be fragmented. A vector of vectors can do this, put a million in each block or something like that might be all you need, and the page fault problem will be minor.
3) when you run out of what the above supports, you need to rethink whatever you are doing and learn to deal with the data in manageable chunks. Its fun and its fast to just dump everything into memory when you can, but if you get into very large things, you have to compromise and break it up. If your machine isnt dedicated to this problem, you may need to break it up sooner so your user can multi-task and stuff.
-- you can make the stack larger, even 'all the machine has' on some platforms. This isnt really what the stack is for, though.
-- note that by using vector, you can ignore where the data lives. Its being handled for you.
-- you can make the stack larger, even 'all the machine has' on some platforms. This isnt really what the stack is for, though.
But this example below, creates the array on heap? (because the parent object is created with new) If correct, why doesn't it allow me to create > 2000000000? Is my hardware limition there?
1 2 3 4 5 6 7
struct mystruct {
char a[2000000000];
};
int main(){
mystruct * mys = new mystruct;
}
start simple: how much ram do you have, and is your compiler 64 bit or 32?
it works for me, but i had to put the ull code on the constant.
new can throw some errors if you want to set up the code to have it tell you the problem.
but most likely you don't have 2gb or whatever that is free all in one solid block.
why are you doing the struct anyway? I poked this in main and its fine:
char *a = new char[2000000000ull];
a[(2000000000ull)-1ull] = 0;
yours works for me too, it just has an unnecessary struct wrapper.