I am slightly confused about the following code
void foo() {
std::list<A*> list;
for (int i = 0; i < 3; i ++) {
A a = A(i);
list.push_back(&a);
}
for (Iterator it = list.begin(); it != list.end(); it++) {
std::cout << (*it);
}
}
which prints out three times the object a with constructor argument 2, i.e. the last object constructed in the loop.
What am I doing wrong here?
You have a list of dangling pointers.
for (int i = 0; i < 3; i ++) {
A a = A(i);
list(&a);
}
In each iteration, this loop creates an object of type A, which is immediately destroyed when the iteration completes. So the contents of the list are undefined. You would need something like this:
for (int i = 0; i < 3; i ++) {
A* a = new A(i);
list(a);
}
...but don't forget to delete them all in another loop when you're done with the list.
The variable a is local to the first for loop, so it is destroyed at the end of each iteration of the loop. This means that after the loop finishes, all three pointers in list point to objects that no longer exist. Dereferencing those pointers causes undefined behaviour.
If you'd like to worry less about remembering to de-allocate the allocated memory (and have a nicer less error prone code) you should use unique_ptr or shared_ptr (read about them and shoose whichever fits your needs best).
Here is a small example (notice how the elements in the vector get deleted when the vector goes out of scope):
cout<<"Scope begins"<<endl;
{
vector< unique_ptr<A> > v;
for (int i=0; i<5; ++i){
v.push_back(unique_ptr<A>(new A(i)) );
}
}
cout<<"Scope ends"<<endl;
Live demo here.
Related
I'm trying to delete my 2D array, but I consistently get errors when I try to delete it, we have to work backwards so I delete the elements first, then the column array, then the row array. here is my code for the constructor in my class, MyMatrix:
private:
int m; //rows
int **ptr; //ptr to first dimension
int n; // columns
public:
MyMatrix() //constructor
{
m = 0;
n = 0;
ptr = new int*[m];
int *length_arr = new int[m];
for (int i = 0; i <= m-1; i++)
{
*(ptr+i) = new int[n];
*(length_arr+i) = n;
}
}
and my destructor looks like this:
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
the error I'm getting is:
assg7(2677,0x100de3d40) malloc: *** error for object 0x12d606804: pointer being freed was not allocated
I've wracked my brain for where I can fix this, for context, I'm doing an assignment with operator overloading. I specifically need a delete function to work properly for my = assignment overloading since I want to delete and again reallocate memory to equate two matrices, but the terminal is showing malloc errors and is thus not equating the matrices.
for additional info here is my = overloading code:
void operator = (const MyMatrix &obj)
{
if(n == obj.n && m == obj.m)
{
//for loop to equate elements in this-> to the elements of the passed object
}
else
{
for(int i = 0; i <= m-1; i++)
{
for (int j = 0; j <= n-1; j++)
{
delete ((*(ptr+i))+j);
}
delete[] *(ptr+i);
}
delete[] ptr;
// the code for assigning new memory according to the passed objects rows and colums goes here
//then for loop to equate elements in this-> to the elements of the passed object
}
}
thanks.
You have two "levels" of new, so three "levels" of delete can't be right.
Spell out your deletion loop, using indexing instead of pointer arithmetic:
First iteration:
delete ptr[0]+0;
delete ptr[0]+1;
...
delete ptr[0]+n-1;
delete [] ptr[0];
Second iteration:
delete ptr[1]+0;
delete ptr[1]+1;
...
delete ptr[1]+n-1;
delete [] ptr[1];
You're passing to delete a pointer to the first element of ptr[0], a pointer to the second element of ptr[0], a pointer to the third element of ptr[0], ...
But the things you allocated were ptr[0], ptr[1], ... ptr[m-1], not their individual elements.
Remove the innermost deletion loop.
(And don't mess around with pointer arithmetic when you can use indexing.)
I don't know how you would want to allocate memory space by m length if it is set to 0 by default.
To me it looks like you set m = 0 and then try to allocate by 0 length or how do you control the length of your dimensions?
Maybe edit your constructor to:
MyMatrix(int m, int n)
{
this->m = m;
this->n = n;
...
In below code, I expect 1 to be initialized in all the 10 elements in x array. But, it doesn't seem to be working. May I know what I am missing here?
int main() {
int *x = new int[10];
for(int i =0; i <10; ++i){
*x = 1;
x++;
}
for(int i = 0; i < 10; ++i)
std::cout<<i<<" is "<<x[i]<<std::endl;
return 0;
}
By the time you end the initialization loop, your x is pointing beyond the last allocated element. Before second forloop you need to readjust x to point to start of memory
x -= 10;
Even better would be to keep your walking pointer as a copy
int *xcopy = x;
for(int i =0; i <10; ++i){
*xcopy = 1;
xcopy++;
}
Or use indexing to update the value
for(int i =0; i <10; ++i){
x[i] = 1;
}
You're incrementing x in the first loop, so after that it points past the end of the array. The second loop uses that new value to read from memory beyond the end, giving undefined behaviour.
The best option is to stop juggling pointers, with the bonus feature of fixing the memory leak:
std::vector<int> x(10, 1);
for(size_t i = 0; i < x.size(); ++i) {
std::cout<<i<<" is "<<x[i]<<std::endl;
}
Otherwise, you could assign to x[i] rather than *x in the first loop and leave x unmodified; or you use a copy of the pointer, or undo the modification after the loop.
Your code has undefined behavior, as you're accessing some random memory (you have changed x).
You should not change x (the pointer). Instead, you can use x[ i ] = 1; or use some other temp pointer to "loop over" x.
You can also decrement x, as #Mohit Jain states, but I wouldn't recommend changing where x points at all.
I am trying to learn C++ by firstly going through the low level details before I start using abstractions such as std::copy or memcpy. Currently I am stuck in trying to figure out why this code is never assigning into "sortedArray" variable, when looking with debugger I dereference the value from "data" correctly but it is never assigned to "sortedArray". I see value such as "-842150451" instead of "14" for first value. Can you please help me figure out what I am doing wrong ? And any other issues there may be that I do not see or advice would be greatly appreciated !
void swap(int* bigger, int* smaller){
*bigger += *smaller;
*smaller = *bigger - *smaller;
*bigger = *bigger - *smaller;
}
int* bubbleSort(int *data, int size){
bool swapped = true;
int *sortedArray = (int*)malloc(size*sizeof(int));
for (int i = 0; i < size;i++){
*(sortedArray++) = *(data++);
}
while (swapped){
swapped = false;
for (int i = 1; i <= size - 1; i++){
if (sortedArray[i - 1] > sortedArray[i]){
swap(&sortedArray[i - 1], &sortedArray[i]);
swapped = true;
}
}
size--;
}
return sortedArray;
}
*(sortedArray++) = *(data++); modifies the pointer so it no longer points to the start of the allocated memory. So, later on sortedArray[i] is whatever happens to be in memory past the array, and accessing it is undefined behavior.
If you must use pointers, a quick fix is to use a temporary one, like:
int *sortedArray = (int*)malloc(size*sizeof(int));
int* s = sortedArray;
for (int i = 0; i < size;i++){
*s++ = *data++;
}
Another way would be:
int *sortedArray = (int*)malloc(size*sizeof(int));
for (int i = 0; i < size;i++){
sortedArray[i] = data[i];
}
But, the best way would be to use standard containers and algorithms, like vector and sort.
Here's a demo of the first fix in action.
Change
*(sortedArray++) = *(data++);
to
sortedArray[i] = data[i];
You need to leave intact the pointer to the block of memory you allocated, so you can use it (and free it) later.
Note, there is nothing to be gained by using the *(x+y) syntax instead of x[y], they are equivalent but the latter is easier to read.
In C++ you should not use malloc. Instead use new int[size]. For int there is no difference other than reduced risk of making a typo, however for non-trivial types malloc will not construct them correctly.
That is not C++ at all. You can write generic code that takes a begin iterator and an end iterator in order for it to work with any kind of container that supports such semantic.
template<typename IT>
void bubble_sort(IT begin, IT end) {
while (true) {
bool swapped = false;
for (IT i = begin; i != end-1; i = i+1) {
if (*i > *(i+1)) {
std::iter_swap(i, i+1);
swapped = true;
}
}
if (swapped == false) return;
}
}
Live demo
Where std::iter_swap is like std::swap but works on iterators. You can see iterators as a pair of pointers to the beginning and (past the) end of a container.
You first pointer sortedArray points to some allocated memory.
Then in the first for loop you increment the pointer. not it doesn't point to that memory anymore.
Simply use a temporary pointer for the memory copy.
int* t = sortedArray ;
And now use t in your for loop which copies the data.
Instead of the temporary variable, you can rather count the number of times you called sortedArray++ in your for loop.
If you take a look: for (int i = 0; i < size;i++) you will see that the loop took exactly size number of iterations.
Just subtract size from the pointer after the loop and you point back to your allocated memory.
sortedArray -= size ;
I have an array of pointers to vectors vector<int> *F[12]; and I wish to initialize some vectors and store their addresses in F.
for(uint i = A; i <= B; ++i){
vector<uint> newvec(pow2(i), 0);
F[i] = &newvec;
}
But when I try to access them later, I find that they are not all zero:
for(uint i = A; i <= B; ++i){
for(uint j = 0; j <= pow2(i); ++j){
if((*F[i]).at(j) != 0){
cout << i << "/" << j << "/" << (*F[i]).at(j) << "|";
}
}
}
I assume this has something to do with the scope of the declared vector. Why has the memory been freed? Do I have to use malloc and create a vector from that?
newvec is being created on the call stack each iteration. Each time through the loop you create it, make a pointer to it, then it vanishes. You want to use the 'new' operator to create a longer-lasting instance of the vector in the heap.
newvec goes out of scope when the loop exits. Any existing reference or pointer to it is invalid at that point. You'll need to declare the object at the appropriate scope (I don't know what that is for you in this case, but certainly outside the for loop).
I don't understand why the following does not work:
queue<int*> q;
int counter = 1;
for (int i = 0; i < 3; i++) {
int a[1] = {counter};
q.push(a);
counter++;
}
while (!q.empty()) {
int *top = q.front();
q.pop();
cout << top[0] << endl;
}
It should print out: 1 2 3, but instead 3 3 3 is printed out. This is because the pointers in the queue are all the same after each run through the loop. Why does that happen?
You are storing pointers to local variables and using those pointers after the local variables they point to have gone out of scope.
In other words: you are invoking Undefined Behavior.
Result: It should not print out "1 2 3". It doesn't have to do anything and is allowed to do whatever it likes. "3 3 3" seems reasonable to me, as it is also allowed to crash.
int a[1] = {counter};
q.push(a);
Not correct. It invokes undefined behvaiour, as a doesn't exist outside the curly braces (the for-loop block). Even if it were well-defined, your code has another problem, all the items in queue is same, as a (the same memory) gets used repeatedly in the loop.
The solution is this:
int *a = new int[1];
a[0] = counter;
q.push(a);
If you do so, then you've to deallocate the memory yourself, of course.
But I'm wondering if every item in queue is just one int,then why not use the following:
queue<int> q;
for (int i = 0; i < 3; i++)
{
q.push(counter);
counter++;
}
Or if you really want array, then why not use std::queue<std::vector<int> > as :
std::queue<std::vector<int> > q;
for (int i = 0; i < 3; i++)
{
std::vector<int> v;
v.push_back(counter);
q.push(v); //dont worry - a copy of the vector is being pushed!
counter++;
}
In this way, you don't have to deal with raw pointers. You don't have to allocate or deallocate memory yourself which in my opinion is a safe approach!
You have undefined behavior, since your declaration of a goes out of scope at the end of the loop where you're pushing it into the queue.
What's probably happening is that the memory location of a gets reused each time through, but there are absolutely no guarantees. You might get a different output next time you run it, or you might get a crash, or demons may fly out of your nostrils.
If you insist on using pointers to integers, the following code does what you want:
#include <queue>
#include <iostream>
int main()
{
std::queue<int*> q;
int counter = 1;
for (int i = 0; i < 3; i++) {
int* a = new int;
*a = counter;
q.push(a);
counter++;
}
while (!q.empty()) {
int *top = q.front();
q.pop();
std::cout << *top << std::endl;
delete top;
}
return 0;
}