I have questions about the destructing process of STL vector as well as array of vectors. The only thing I learned from my teacher is the number of delete is equal to the number of new. I have 3 questions for the array of vector in different contexts. To be convenient, all of the array has 5 vectors. Each vector has 1 element.
1. Array of vectors appears in main.cpp
int main(){
int size = 5;
vector<int> *array_vec = new vector<int>[size];
for(int i=0; i<size; i++){
array_vec[i].push_back{i};
}
delete [] array_vec;
return 0;
}
Question 1: At the end of the main() function, I manually delete the array by delete [] array_vec, but I don't manually free each vectors array_vec[i]. Was the array_vec[i]'s memory released automatically? If yes, when? (before OR after my delete [] array_vec?) The reason why I ask this question is for 2D dynamic array, we must free the inner array before the outer array, so I wonder whether it is the case for the array of vector.
2. Array of vectors appears in a class's method as a temporary variable
Class myClass{
public:
void myMethod(){
int size = 5;
vector<int> *array_vec = new vector<int>[size];
for(int i=0; i<size; i++){
array_vec[i].push_back(i);
}
delete [] array_vec;
}
}
int main(){
myClass myclass;
myclass.myMethod();
/** some other process in the program **/
return 0;
}
Question 2: Was the array_vec[i] released before the myclass.myMethod() returned? OR array_vec[i] will only be released at the end of the entire program?
3. Array of vectors appears in a class as a class property
Class myClass{
public:
vector<int> *array_vec;
public:
~myClass(){
if(array_vec)
delete [] array_vec;
}
void Init(){
int size = 5;
array_vec = new vector<int>[size];
for(int i=0; i<size; i++){
array_vec[i].push_back(i);
}
}
void Use(){
std::cout<<array_vec[0][0]<<std::endl;
}
}
int main(){
myClass myclass;
myclass.Init();
myclass.Use();
/** some other process in the program **/
return 0;
}
Question 3: Is my destructor OK? In my ~myClass() method, I just free the array of vectors array_vec, but I do not know whether those vectors themselves will be free automatically or not? If yes, that will be good. If no, when will they be released? How can I manually free those vectors?
This problem has confused me for a long time. The memory issue is very important for my c++ program, because I need to use array of vectors in a big loop. If the memory is not released correctly, the memory usage will be larger and larger while the program is running. In that case, my program will crash. Really appreciate your help.
All of your examples are fine. std::vector takes care of cleaning up the memory it owns. That's why you use it instead of raw pointers.
In all of the cases you posted, you should use a std::vector<std::vector<int>> instead though. That will free you from having to deal with memory management at all, and help avoid easy mistakes, like the rule of three violation in your third example.
Related
I'm a beginner for C++ and I saw the post here. However, it is very unclear for me what is the benefit of dynamic array.
One advantage is that one can change the length of a dynamic array, here is the code
int *p = new int[10];
// when run out of the memory, we can resize
int *temp = new int[20];
copy(p, temp); // copy every element from p to temp
delete[] p; // delete the old array
p = temp;
temp = nullptr;
Above is for dynamic allocation, it says the array will be on the heap, and need to manually delete it. However, why not use the static array as follow
int array1[10];
int *p = array1;
// when run out of the memory, we can resize
int array2[20];
copy(array1, array2); // copy every elements from array1 to array2;
p = array2;
In this code, we don't need to delete the array1 since it is on the stack area. Here are my question:
what is the benefit of the dynamic array? It seems for me, resizing is not a big issue. People always say the size of static array are fixed, the size of dynamic array is not fixed. Why the size of dynamic array is not fixed. for example, int p=new int[10], the size of p is fixed.
Thanks a lot.
int array1[10];
int *p = array1;
// when run out of the memory, we can resize
int array2[20];
copy(array1, array2); // copy every elements from array1 to array2;
p = array2;
In whichever function, or inner scope, array1 and array2 get declared these arrays get automatically destroyed when the function or inner scope returns. Full stop.
This is why this is called "automatic scope". The fact that there may be a pointer to one of the arrays is immaterial. The array will be gone and any attempt to dereference that pointer will result in demons flying out of your nose.
So if you had any grand designs to continue using this array, in some form or fashion, after returning from the function where they get declared, too bad. It's not going to happen.
On the other hand, after newing something, as long as you properly track the pointer to the newed object(s) they can be used anywhere else, until they get deleted. This function, another function, anywhere. Even a different execution thread.
Having said all of that, you should not be using new or delete either. You should be using C++ library's containers which will correctly handle all memory allocation, deallocation, and copying, for you. In this case, you are simply reinventing what std::vector already does for you, and it will actually do it, in some ways, far more efficient than you can do easily on your own. You just call resize(), and, presto, your vector is bigger or smaller, as the case may be. And, in all other respects the vector will be indistinguishable from your array. It will be very hard to tell the difference.
So, use C++ library's containers. They are your friends. They want you to do memory allocation correctly, on your behalf. Modern C++ code rarely uses new or delete, any more. It's important to understand how it works, but 99% of the time you don't really need it.
Doing your own dynamic array with new int[20] and delete[] etc, is no doubt good for learning how it all works.
In real C++ programs you would use std::vector. Maybe like this:
#include <iostream>
#include <string>
#include <vector>
int main() {
std::vector<std::string> lines;
std::string line;
while (std::getline(std::cin, line)) {
lines.push_back(line);
}
std::cout << "Read " << lines.size() << " lines of input\n";
}
The reason you would use dynamic allocation is so your program can handle any number of lines of any line length. This program can read four lines or 400,000. The std::vector is dynamic. So is std::string.
I have write a code on static and dynamics array, hope this will help.
#include<iostream>
using namespace std;
int main (){
//creating the static array .. rember the syntax of it.
int array[4]= {1,2,3,4}; // size is fixed and can not be changeable at run time.
cout<<"Static Array."<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<4;x++){
cout<<"\t"<<array[x];
}
cout<<endl;
cout<<"Printing using pointer."<<endl;
int*ptr= array;
for(int x=0;x<4;x++){
cout<<"\t"<<*ptr++;
}
//delete [] array ;// error, because we can not free the size from stack
// array[6]= {1,2,3,4,5,6}; //Error: We can not change the size of static array if it already defined.
// we can not change the size of the static aray at run time.
cout<<endl;
cout<<"\n\nDynamic Array."<<endl;
int n=4;
//Creating a dynamic Array, remember the systex of it.
int *array2 = new int [n]; // size is not fixed and changeable at run time.
array2[0]= 1;
array2[1]= 2;
array2[2]= 3;
array2[3]= 4;
cout<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<4;x++){
cout<<"\t"<<array2[x];
}
cout<<endl;
cout<<"Printing using pointer."<<endl;
int*ptr2= array2;
for(int x=0;x<4;x++){
cout<<"\t"<<*ptr2++;
}
cout<<endl<<endl<<endl;
delete array2; //Size is remove at runtime
cout<<"Chnaging the size of dynamic array at runtime... :)";
// Changing the size of the array to 10.. at runtime
array2 = new int [10]; // Array size is now change to 10 at runtime
array2[0]= 1;
array2[1]= 2;
array2[2]= 3;
array2[3]= 4;
array2[4]= 5;
array2[5]= 6;
array2[6]= 7;
array2[7]= 8;
cout<<endl;
cout<<"Printing using index."<<endl;
for(int x=0;x<7;x++){
cout<<"\t"<<array2[x];
}
// free the memory/ heap
delete [] array2;
return 0;
}
Output
please excuse my noobie question..
I have :
class A;
{
public:
A(int i) : m_i(i) {}
int m_i;
}
A newA(i);
{
return A(i);
}
And I want to fill the following vector, but using a loop where an object A is created with a function (newA):
vector<A*> list;
for (int i=0 ; i<3; ++i) { A a = newA(i); list.push_back(&a); }
That works if I use a vector<A> but not with a vector<A*> since all I do is changing the value at &a and pushing 3 times the same pointer &a.
How can I do so that I create a new A every time, and not change the value of the same pointer.
I came up with the following but I hope it's not the only way, since it includes dynamic allocation..
A newA(i);
{
return A(i);
}
vector<A*> list;
for (int i=0 ; i<3; ++i)
{
A a = newA(i);
list.push_back(new A(a));
}
Note that class A is actually huge in memory, hence the pointers.
You should realize the first method is bad:
for (int i=0 ; i<3; ++i) { A a = newA(i); list.push_back(&a); }
You are creating a local object and then storing a pointer to it. Once you leave the loop the object will not exist anymore and you have undefined behavior. As john said there is no sensible way to do what you want to do without using dynamic allocation. As Billy noted instead of using a raw pointer you can use a shared_ptr or unique_ptr and then you don't have to worry about memory management which is possibly why you want to avoid dynamic allocation.
Storing a vector of pointers does not give the vector ownership of the resulting instances of A. There is going to be dynamic allocation involved in order to populate such a structure.
(Of course, in real code you should probably create a vector<unique_ptr<T>> or a vector<shared_ptr<T>> instead of a vector<T*> but that's another topic)
It is the only way, as in your first example the object that you store the pointer to is immediately destroyed at each iteration of the for loop, as it goes out of scope.
I have to insert elements into a pointer to a vector.I have written the following code but it is giving segmentation fault. Could someone please point out what are the errors in this code or how can we do this alternatively.
int main()
{
vector<int> *te;
te->push_back(10);
cout<<te->size()<<endl;
return 0;
}
You never allocate the vector:
vector<int> *te = new vector<int>;
Also, you don't need dynamic allocation. A cleaner way is with automatic storage:
int main()
{
vector<int> te;
te.push_back(10);
cout<<te.size()<<endl;
return 0;
}
vector<int> *te;
te->push_back(10);
You have declared a pointer to a vector; you have not initialized it to point to a valid piece of memory yet. You need to construct a new vector using new.
vector<int> *te = new vector<int>();
You should however not do this. There are very few reasons to maintain a pointer to a vector, and you just made it completely ineffective at managing its own internal memory.
Read a little bit about RAII. This is a technique used to manage dynamically allocated memory via the lifetime of an object. The vector uses this method to clean up its internal, dynamically allocated storage when it goes out of scope.
Maintaining a pointer to the vector prevents it from working correctly, relying on you to call delete yourself, essentially nullifying one major benefit of using a vector over an array in the first place.
you have to first allocate place for the pointer before starting to use it .
vector<int> *te = new vector<int>();
insert this line into your code just after the vector<int> *te;
Note that
If you were to trying to access already defined vector with an pointer you would not have to allocate place for the pointer.
For example;
vector<int> foo={1,2,3,4,5};
vector<int> * te=&foo;
te->push_back(6); // its legal.
Completing #eday solution to access elements
vector<int> foo={1,2,3,4,5};
vector<int> * te=&foo;
te->push_back(6);
cout << (*te)[2] << endl; // > 3
Your problem is that you created a pointer to a vector without creating a vector to which it points. Here's a small example where you create a vector, then use the pointer to do something to it, and then check the original vector to see the result:
#include <iostream>
#include <vector>
using namespace std;
int main(){
vector<int> myvector;
vector<int>* te = &myvector;
int N = 5;
for(int i = 0; i < N; i++){
te->push_back(N - i);
}
cout<<"te->size() "<<te->size()<<endl;
for(int i = 0; i < N; i++){
cout<<"myvector["<<i<<"] = "<<myvector[i]<<endl;
}
return 0;
}
In C++, Lets say I'm creating an array of pointers and each element should point to a data type MyType. I want to fill this array in a function fillArPtr(MyType *arPtr[]). Lets also say I can create MyType objects with a function createObject(int x). It works the following way:
MyType *arptr[10]; // Before there was a mistake, it was written: "int *arptr[10]"
void fillArPtr(MyType *arptr[])
{
for (int i = 0; i < 10; i++)
{
MyType myObject = createObject(i);
arptr[i] = new MyType(myobject);
}
}
Is it the best way to do it? In this program how should I use delete to delete objects created by "new" (or should I use delete at all?)
Since you asked "What is the best way", let me go out on a limb here and suggest a more C++-like alternative. Since your createObject is already returning objects by value, the following should work:
#include <vector>
std::vector<MyType> fillArray()
{
std::vector<MyType> res;
for (size_t i = 0; i != 10; ++i)
res.push_back(createObject(i));
return res;
}
Now you don't need to do any memory management at all, as allocation and clean-up is done by the vector class. Use it like this:
std::vector<MyType> myArr = fillArray();
someOtherFunction(myArr[2]); // etc.
someLegacyFunction(&myArr[4]); // suppose it's "void someLegacyFunction(MyType*)"
Do say if you have a genuine requirement for manual memory management and for pointers, though, but preferably with a usage example.
Your method places the array of pointers on the stack, which is fine. Just thought I'd point out that it's also possible to store your array of pointers on the heap like so. Youd do this if you want your array to persist beyond the current scope
MyType **arptr = new MyType[10];
void fillArPtr(MyType *arptr[])
{
for (int i = 0; i < 10; i++)
{
MyType myObject = createObject(i);
arptr[i] = new MyType(myobject);
}
}
If you do this, don't forget to delete the array itself from the heap
for ( int i = 0 ; i < 10 ; i++ ) {
delete arptr[i];
}
delete [] arptr;
If you're going to use vector, and you know the size of the array beforehand, you should pre-size the array. You'll get much better performance.
vector<MyType*> arr(10);
for (int i = 0; i < 10; i++)
{
delete arptr[i];
arptr[i] = 0;
}
I suggest you look into boost shared_ptr (also in TR1 library)
Much better already:
std::vector<MyType*> vec;
for (int i=0; i<10; i++)
vec.push_back(new MyType(createObject(i));
// do stuff
// cleanup:
while (!vec.empty())
{
delete (vec.back());
vec.pop_back();
}
Shooting for the stars:
typedef boost::shared_ptr<MyType> ptr_t;
std::vector<ptr_t> vec;
for (int i=0; i<10; i++)
vec.push_back(ptr_t(new MyType(createObject(i)));
You would basically go through each element of the array and call delete on it, then set the element to 0 or null.
for (int i = 0; i < 10; i++)
{
delete arptr[i];
arptr[i] = 0;
}
Another way to do this is with an std::vector.
Use an array of auto_ptrs if you don't have to return the array anywhere. As long as you don't make copies of the auto_ptrs, they won't change ownership and they will deallocate their resources upon exiting of the function since its RAII based. It's also part of the standard already, so don't need boost to use it :) They're not useful in most places but this sounds like a good one.
You can delete the allocated objects using delete objPtr. In your case,
for (int i = 0; i < 10; i++)
{
delete arptr[i];
arptr[i] = 0;
}
The rule of thumb to remember is, if you allocate an object using new, you should delete it. If you allocate an array of objects using new[N], then you must delete[] it.
Instead of sticking pointers into a raw array, have a look at std::array or std::vector. If you also use a smart pointer, like std::unique_ptr to hold the objects within an std::array you don't need to worry about deleting them.
typedef std::array<std::unique_ptr<MyType>, 10> MyTypeArray;
MyTypeArray arptr;
for( MyTypeArray::iterator it = arptr.begin(), int i = 0; it != arptr.end(); ++it ) {
it->reset( new MyType( createObject(i++) ) );
}
You don't need to worry about deleting those when you're done using them.
Is the createObject(int x) function using new to create objects and returning a pointer to this?. In that case, you need to delete that as well because in this statement
new MyType( createObject(i++) )
you're making a copy of the object returned by createObject, but the original is then leaked. If you change createObject also to return an std::unique_ptr<MyType> instead of a raw pointer, you can prevent the leak.
If createObject is creating objects on the stack and returning them by value, the above should work correctly.
If createObject is not using new to create objects, but is creating them on the stack and returning pointers to these, your program is not going to work as you want it to, because the stack object will be destroyed when createObject exits.
i ve created two dimensional array inside a function, i want to return that array, and pass it somewhere to other function..
char *createBoard( ){
char board[16][10];
int j =0;int i = 0;
for(i=0; i<16;i++){
for( j=0;j<10;j++){
board[i][j]=(char)201;
}
}
return board;
}
but this keeps giving me error
Yeah see what you are doing there is returning a pointer to a object (the array called board) which was created on the stack. The array is destroyed when it goes out of scope so the pointer is no longer pointing to any valid object (a dangling pointer).
You need to make sure that the array is allocated on the heap instead, using new. The sanctified method to create a dynamically allocated array in modern C++ is to use something like the std::vector class, although that's more complicated here since you are trying to create a 2D array.
char **createBoard()
{
char **board=new char*[16];
for (int i=0; i<16; i++)
{
board[i] = new char[10];
for (int j=0; j<10; j++)
board[i][j]=(char)201;
}
return board;
}
void freeBoard(char **board)
{
for (int i=0; i<16; i++)
delete [] board[i];
delete [] board;
}
The best approach is create a board class and make the ctreateBoard function its constructor:
class Board {
private:
char mSquares[16][10];
public:
Board() {
for(int i=0; i<16;i++){
for( int j=0;j<10;j++){
mSquares[i][j]=201;
}
}
// suitable member functions here
};
For information on how to use such a class, there is no substitute for reading a good book. I strongly recommend Accelerated C++ by Andrew Koenig and Barbra Moo.
This approach will not work. If you return a pointer to a local variable you'll run into undefined behaviour. Instead allocate an array on heap with new and copy data into it manually indexing it.
I would really recommend using STL vector<> or boost/multi_array containers for this.
If you must use arrays, then I would recommend using a typedef to define the array.
typedef char[16][10] TBoard;
You could also return
char**
...but then you would need to typecast it to the correct size in order to index it correctly. C++ does not support dynamic multiple dimension arrays.
Also as others have suggested you can't return an object on the stack (i.e., local variable)
Don't return pointer to a local variable, as other mentioned. If I were forced to do what you want to achieve, first I'd go for std::vector. Since you haven't learnt std::vector, here is another way:
void createBoard(char board[16][10])
{
int j =0;int i = 0;
for(i=0; i<16;i++){
for( j=0;j<10;j++){
board[i][j]=(char)201;
}
}
}
You should return char** instead of char*
The simple answer to your question is char**.
Having said that, DON'T DO IT !
Your "board" variable won't last outside createBoard().
Use boost::multi_array and pass it as a reference to createBoard() or return it directly (but if you do that, it will be copied).
You must not return a pointer to a functions local variables because this space gets overwritten as soon as the function returns.
The storage associated with board is on the function's stack.