pass unigue_ptr as shared_ptr into a vector - c++

Here is a test to understand more about shared_ptr and unique_ptr:
#include <string>
#include <memory>
#include <vector>
std::vector<std::shared_ptr<int> > vec_ptr;
int* get()
{
for (size_t i = 0; i < 1; ++i)
{
vec_ptr.push_back(std::make_unique<int>());
}
return vec_ptr.back().get();
}
int main()
{
int obj = 5;
int* ptr = get();
ptr = &obj;
std::cout << *ptr << std::endl;
std::cout << *vec_ptr[0].get() << std::endl; //expect: 5, but it is 0
}
Apparently nothing is assigned to the vec_ptr. Could someone please explain it to me?

It seems you wanted to do:
*ptr = obj;
instead of
ptr = &obj;
The former copies the integer obj into the space pointed to by ptr. The latter (which you're doing) re-points ptr to point at obj.

Here is what you have in this program:
vec_ptr contains 3 elements, each of them is 0.
obj, with a value of 5.
ptr, which points to obj.
So the program prints the correct values of 5 and 0. If you want to change the value of one of the pointers, then you should assign it like this:
*ptr = obj;
Then, ptr will point to the last element of vec_ptr (as returned by get()), which will have the value of 5. However, your last line will still print 0, because that prints the first element of the vector, not the last.

Related

The lifetime of a pointer reference in C++

I wrote some code that involves moving and changing variables in C++. Below is what I have wrote.
#include <iostream>
void six(int*& ptr) {
int s = 6;
ptr = &s;
}
int main() {
int f = 5;
int* ptr = &f;
std::cout << *ptr << '\n';
six(ptr);
if (ptr) {
std::cout << *ptr;
}
else {
std::cout << "null\n";
}
return 0;
}
so this prints:
5
6
I tried another code, adding a single line:
#include <iostream>
void six(int*& ptr) {
int s = 6;
ptr = &s;
free(&s); // added line
}
int main() {
int f = 5;
int* ptr = &f;
std::cout << *ptr << '\n';
six(ptr);
if (ptr) {
std::cout << *ptr;
}
else {
std::cout << "null\n";
}
return 0;
}
Obviously, this gives an error after printing 5 because what the modified pointer is pointing is not available when called the second time.
However, I am confused at the first case. When calling six in the main function, variable s is not in the main scope, but the value itself still continues to remain in the memory to be referenced. Doesn't C++ automatically destroy variables and clean them when it goes out of the scope? Is this a memory leak?
The first case is not a memory leak, but an undefined behaviour because your variable go out of scope.
In this case you don't know when the memory will be cleaned(replaced) o reallocated.
So in some case the result can be correct but it's a pure question of luck.

unique_ptr with array crash when calling reset

Can someone explain the crash here?
#include <iostream>
#include <memory>
int main() {
int *num1 = new int(5), *num2 = new int(18);
std::unique_ptr<int> numptr = std::unique_ptr<int>(num1);
std::cout << *numptr.get() << '\n'; // 5
numptr.reset(num2);
std::cout << *numptr.get() << '\n'; // 18
int a[5] = {0,2,4,6,8}, b[5] = {0,3,6,9,12};
std::unique_ptr<int[]> u = std::unique_ptr<int[]>(a);
std::cout << u[3] << '\n'; // 6
u.reset(b);
std::cout << u[3] << '\n'; // Crash. Why??? Should output 9, right?
}
There is no crash when calling reset with std::unique_ptr<int>, so why the crash with std::unique_ptr<int[]>. As I see it, u takes ownership of b, and then deletes a. So u[3] should be b[3] = 9 which should work fine because b is not deleted. What's going on here?
You wrap your unique_ptr around an array, which has automatic storage duration and its memory will be released by the runtime. At the end of your program, unique_ptr tries to release the same memory. Basically the line u.reset(b); is equivalent to delete[] a; // then set u to point to b.
If you try a simple program like
int main()
{
int arr[10];
delete[] arr; // runtime error here
}
you'll get exactly the same error. You should never use smart pointers with non-dynamic objects.

pointer based linked list gives segmentation error

#include "AirlineReservationSystem.h"
struct test{
int num;
test* tNext;
};
int main()
{
test* a;
a = new test;
a->num = 8;
a->tNext = new test;
test* ptr = a;
ptr = ptr->tNext;
ptr->num = 9;
cout << ptr->num;
ptr = a;
cout << ptr->num;
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
cout << ptr->num;
return 0;
}
I am trying to understand here why this code gives a segmentation error. Disregard the include at the start, It does nothing.
I am very very very new at this and trying to understand pointers and linked lists better and make some practice yet i am unable to see what i am doing wrong.
Program itself prints the first two couts but crashed at while statement which means there must be some problem with it, if someone could explain to me what that problem really is and what i am missing, it would be great. Thanks.
You have initialized ptr->num = 9, but you have not initialized ptr->tNext to anything.
Now let's examine the following piece of code:
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
Iteration #1:
Most likely ptr->tNext != NULL, so you enter the loop and set ptr = ptr->tNext.
Now ptr is most likely pointing to an invalid memory address.
Iteration #2:
ptr is most likely pointing to an invalid memory address.
Therefore, ptr->tNext would most likely yield an illegal memory access.
When you create the second test, you do not initialize the pointer member in the struct.
This means that it points to some random memory address which is not a test instance (although I heard that some compilers will automatically make it point to NULL, never seen this in action though). Mostly the memory that is reserved for the struct is not cleared by default, so any content that was there remains "in the struct" until you assign it with something else.
If you don't assign it a new value the application will break when trying to dereference the memory.
So to fix this:
struct test{
test() : tNext(NULL) {} // ADD THIS AND ...
~test() { if(tNext) delete tNext; } // ADD THIS AND ...
int num;
test* tNext;
};
int main()
{
test* a;
a = new test;
a->num = 8;
a->tNext = new test;
test* ptr = a;
ptr = ptr->tNext;
ptr->num = 9;
cout << ptr->num;
ptr = a;
cout << ptr->num;
while ( ptr->tNext != NULL){
ptr = ptr->tNext;
}
cout << ptr->num;
delete a; // ADD THIS
return 0;
}
The first line is a constructor that sets the pointer to NULL which will prevent the pointer to point to random memory. The second line is the destructor which will clean up your nested structure recursively.
This behavior is desired because your code will exit from the while giving segmentation fault as your ptr->tNext!=NULL condition is not met at the last node also. So for the last node the ptr is set with a garbage value and hence when ptr->tNext!=NULL is executed, it gives segmentation fault error.
To avoid this, add the following line after ptr->num = 9;
ptr->tNext = NULL;
(1) Probably you are missing initialization of tNext to NULL.
Try changing your definition to:
struct test{
int num;
test* tNext;
test():num(0),tNext(NULL) {} // contructor initializing the members to default values
};
(2) You dont know if ptr is NULL or not inside while condition and in that case it is likely to give segmentation fault. Add null check on ptr in while () as well like this:
while (ptr && ptr->tNext != NULL){ // ptr->tNext is executed only when ptr is valid
ptr = ptr->tNext;
}

Random array value after return c++

My problem is I don't know what happens with data that I put into my arrays and how to make them stay in array. While debugging it is clear that arr gets initialized with zeros and arr2 with {1,2,3}. Functions however return some random values.. can someone help me to point out what it should be like?
#include <iostream>
#include <algorithm>
#include <vector>
class A
{
private:
double arr[5];
public:
A()
{
std::fill( arr, arr + 5, 0.0 );
};
~A() {};
void setArr( double arrx[] )
{
for ( int i = 0; i < 5; i++ )
arr[i] = arrx[i];
}
double* getArr(void) { return arr;}
};
int* probe()
{
int arr2[3] = {1,2,3};
return arr2;
}
int main()
{
A ob1;
double rr[5] = {1,2,3,4,5};
ob1.setArr(rr);
std::cout << ob1.getArr() << std::endl;
std::cout << probe() << std::endl;
system("Pause");
}
EDIT:
Now thanks to you i realize I have to loop the get** function to obtain all values. But how can I loop it if my planned usage is to write it like you see below into some file?
pF = fopen ("myfile.csv","a");
if (NULL != pF)
{
char outp[1000];
sprintf_s(outp, 1000, "%6d,\n", ob1.getArr());
fputs(outp, pF);
fclose(pF);
}
In
std::cout << ob1.getArr() << std::endl;
std::cout << probe() << std::endl;
You are actually printing the pointers (address), not the values which are double or int. You need to loop through all the elements of the array to print them.
As pointed out by P0W that accessing element of probe() has undefined behaviour, in that case you must make sure that the array should be valid. One quick solution is that declare the array static in the function.
As you want to write the value in the file
pF = fopen ("myfile.csv","a");
if (NULL != pF)
{
char outp[1000];
int i;
int retsofar=0;
for(i=0;i<5;++i)
retsofar+=sprintf_s(outp+retsofar, 1000-retsofar, "%6d,\n", ob1.getArr()[i]);
fputs(outp, pF);
fclose(pF);
}
you are trying to print the addresses of arrays returned by ob1.getArr() and probe() methods. Every time you are getting different addresses. If you want to print array, use loop.
In probe(), you are creating an array on stack and simply returning it's pointer. It is not safe. When it goes out of scope, its values can be overwritten and you may get un expected behaviour. So create that array on heap.

Access object array using pointer

This is my sample program
#include "stdafx.h"
class B
{
public:
int i,j;
};
class A
{
public:
B b[2];
A()
{
b[0].i = 1;
b[0].j = 2;
b[1].i = 3;
b[1].j = 4;
}
B* function()
{
return b;
}
};
int _tmain(int argc, _TCHAR* argv[])
{
A a;
B* obj = new B();
obj = a.function();
return 0;
}
I have to get the array of b objects(ie, need all the values, b[0].i, b[0].j,b[1].i and b[1].j)
But when I tried it with this code, only one object is returned.
What you state in the question is not true. Two objects are indeed returned. Access them with obj[0] and obj[1].
I guess you are looking at obj under the debugger and the IDE cannot know that you mean for your pointer obj to be an array of two objects. So the tooltips will only show the first object, obj[0], or *obj. But the other object, obj[1] is definitely there.
Add the following line after the call to a.function:
printf("%d, %d, %d, %d\n", obj[0].i, obj[0].j, obj[1].i, obj[1].j);
and you will see this output:
1, 2, 3, 4
Note that there is no point in the line B* obj = new B(); since you immediately overwrite obj. You should do it this way:
B* obj = a.function();
Your code is also a little dangerous in that you must keep a alive at least as long as you are making references to obj.
This code
B* function()
{
return b;
}
returns the pointer to the first element of array
B b[2];
which can be dereferenced applying pointer arithmetics and/or operator [].
Yes, you are actually returning the a pointer to the array b[2]. What you want to do now is to iterate through the items in that pointer. You can print them by adding this lines to you code:
A a;
B *obj = a.function();
std::cout << obj[0].i << ", " << obj[0].j << "; " << obj[1].i << ", " << obj[1].j << std::endl;
And of course, including iostream at the beginning of your file:
#include <iostream>