Delete objects via reference c++ - c++

I got this problem which I could not explain today.
int main(){
vector<int> vec = subroutine();
...
delete(&vec);
}
vector<int>& subroutine(){
vector<int>* vec = new vector<int>();
//Init the vec
for(int i=0;i<vec.size();i++){
...
}
return *vec;
}
And it came with an error as:
double free or corruption (out): 0X00007fffa145ff50
It's definitely the problem with the line:
delete(&vec);
But I just can't explain, why there is a double free?

You are calling delete on something that is not allocated with new because you are making a copy of the newed vector. You could "correct" your code by not copying the vector:
vector<int>& vec = subroutine();
but this kind of function really is asking for trouble. The correct way to fix this would be to return a vector by value.
vector<int> subroutine() {
vector<int> vec;
//Init the vec
for(int i=0;i<vec.size();i++){
...
}
return vec;
}

When you return from the function, a copy of the vector is made and, at this point, the newed memory is leaked and cannot be reached; hence the error, you are trying to delete something on the stack (and not on the heap).
I don't see a reason why you need the new; you could try this instead.
vector<int> subroutine(){
vector<int> vec;
//Init the vec
for(int i=0;i<vec.size();i++){
//...
}
return vec;
}
Return the vector by value.

vector<int> vec = subroutine(); here you make a copy. You do not return the pointer. You return a whole object that the pointer refers to, on this line return *vec;.
Thus, the vec from main is deleted explicitly by you, and then again when its scope ends.
Moreover, the vec from subroutine is never freed.

Related

C++ my copy constructor fails to move the memory to a new area

So I've recently started to work on getting my own vector class working and I'm a little bit stuck on my copy constructor. I'm obviously rather new to c++ and was hoping the good guys at stack overflow could help me out a bit. So I got this copy constructor which copies the actual ptr being used, the end index of the ptr (the elements the user can use) and the actual capacity/reserved memory the ptr has, plus the size of the used memory.
vector(const vector &other) : storage(other.storage), capacity(other.capacity),
endIndex(other.endIndex), m_size(other.m_size)
{
T* storage = new T[capacity];
memcpy(storage, other.storage, sizeof(T) * capacity);
}
The issue is that while it seemingly copies the information successfully, if one of the objects run out of scope, the information, or at least some of it gets deleted. If I also do a push_back on one of the vector objects, it happens on both of them. So it's fairly safe to say that they share address for their ptr. For example if I run this code in my main function
int main()
{
vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
vector<int> vec1 = vec;
for (int i = 0; i < vec1.size(); i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
I will get this error message
5
55
500
free(): double free detected in tcache 2
Aborted (core dumped)
I'm assuming this is because the ptr gets deleted while going through the loop and it in turn crashes the program in a nice fashion. Another example of the push_back is
int main()
{
vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
vector<int> vec1 = vec;
vec.push_back(55);
for (int i = 0; i < vec1.size() + 1; i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
Where you can obviously see that i actually push_back on the original vector object and not the new one, i even have to increase the for-loops scope to be able to see the object on the new vector, hinting at the size integer in the new object is unchanged from before. Output of this code is:
5
55
500
55
free(): double free detected in tcache 2
Aborted (core dumped)
I don't expect anyone to take time out of their day to debug my code, I don't want that. I'm merely asking for a pair of professional eyes to glance over it and help a newbie out. Thanks in advance.
There are multiple issues with your code.
The first and foremost one is this:
T* storage = new T[capacity];
That storage is not the same as the member variable storage. It is a local variable that just happens to have the same name. Once the copy constructor is complete, you haven't done anything except leak memory.
In addition, you have this:
vector(const vector &other) : storage(other.storage),
This assigns the pointer other.storage to this. This is actually where the double-free comes from. You are doing a shallow copy, thus when this and other are destroyed, the same pointer value will be used in the call to delete [] in the destructor.
The third issue is this:
memcpy(storage, other.storage, sizeof(T) * capacity);
This will not work for types that are not trivially-copyable. Let's say you fix all the issues except this one. This code will fail miserably:
vector<std::string> s;
and the reason is that you can't use memcpy to copy std::string objects, since std::string is not trivially-copyable.
The fix is to use std::copy, not memcpy, since std::copy is (should be) smart enough to either do a memcpy for trivially-copyable types, or a plain loop for non trivially-copyable types.
The last issue is your naming of the class vector. Note that there already is a std::vector in C++. Either change the name to something else, or place your class in its own namespace so that a name clash will not occur if you happen to #include <vector> somewhere.
Putting that all together, you will have this (not compiled, forgive any syntax errors):
#include <algorithm>
namespace myVector
{
template <typename T>
class vector
{
private:
// your member variables
public:
//...
vector(const vector &other) : capacity(other.capacity),
endIndex(other.endIndex), m_size(other.m_size)
{
storage = new T[capacity]();
std::copy(other.storage, other.storage + other.m_size, storage);
}
vector& operator=(const vector& other)
{
// see later
}
~vector()
{
delete [] storage;
}
//...
};
}
Then the main could be this:
#include <myvector>
int main()
{
myVector::vector<int> vec;
vec.push_back(5);
vec.push_back(55);
vec.push_back(500);
myVector::vector<int> vec1 = vec;
for (int i = 0; i < vec1.size(); i++)
{
std::cout << vec1[i] << std::endl;
}
return 0;
}
Once this is all done and corrected, to complete the rule of 3, the assignment operator can be simply this:
vector& operator=(const vector& other)
{
if ( &other != this )
{
vector temp(other);
std::swap(temp.capacity, capacity);
std::swap(temp.m_size, m_size);
std::swap(temp.endIndex, endIndex);
std::swap(temp.storage, storage);
}
return *this;
}
The above is using the copy/swap idiom
The problem is simple, but hard to see in your own code since you know what you want it to do. You could track it down by stepping through in a debugger and examining the value and address of storage scrupulously on every line.
Seriously, try doing that first.
OK, so here is it:
vector(const vector &other)
: storage(other.storage) // 1. copy the pointer, so this->storage is shared
, capacity(other.capacity)
, endIndex(other.endIndex)
, m_size(other.m_size)
{
// 2. declare a local variable called storage which shadows this->storage
T* storage = new T[capacity];
memcpy(storage, other.storage, sizeof(T) * capacity);
}
You do not want the storage to be shared, so you should never initialize storage(other.storage). There is literally no reason to do this in your code. If you just initialize it to nullptr you would have realized very quickly that the local variable in the constructor body was wrong.
Simply removing the T* from T* storage = ... will fix your immediate problem. All the other suggestions about using std::copy instead of memcpy, and how better to structure your code are good ones, and you should do those too.

Pointer with vectors

Can someone please tell, what is wrong with this code? The purpose is to find the factors from a given number 'n'.
vector <int> * factor(int *n){
vector<int> * arr;
for(int i=1;i<=*n;i++){
if(*n%i==0){
arr->push_back(i);
}
}
return arr;
}
int main(){
int n,j=0;
vector<int> *arr;
cin>>n;
arr = factor(&n);
for(auto it=arr->begin();it!=arr->end();++it){
cout<<*it;
}
return 0;
}
Your 1st problem is that you pass an address of a local variable to a function that expects to read the content of that address. You haven't allocated memory for that variable so it is a "temporary" variable which is saved on the stack, and not on the heap, so factor cannot access it.
If you feel like unnecessarily allocating memory, you should define n as a pointer, allocate memory with "new" and pass the pointer to factor, like so:
int* n = new int;
arr = factor(n);
However, you could've easily passed factor the local variable as is, so it'll receive a copy of it. That requires you to edit your function and remove the *'s from the n's.
Your second problem is defining arr as a pointer to vector. All it does is create a variable which says : "hey, i can point you in the direction where the real vector object is at!", but there is no such object since you haven't allocated memory for it.
For this code, it is best to work with local variables, nothing here requires memory allocation, so i would suggest the following edit:
vector <int> factor(int n){
vector<int> arr;
for(int i=1;i<=n;i++){
if(n%i==0){
arr.push_back(i);
}
}
return arr;
}
int main(){
int n,j=0;
vector<int> arr;
cin>>n;
arr = factor(n);
for(auto it=arr.begin();it!=arr.end();++it){
cout<<*it;
}
return 0;
}

Why my I can't return an array?

I'm trying to return a pointer to an array from a function but I have an issue. When I try to output like this:
#include <iostream>
using namespace std;
int* Somma_Array(int[],int[],int);
int main()
{
int n;
cin>>n;
int A[n],B[n];
for(int i=0;i<n;i++)cin>>A[i];
for(int i=0;i<n;i++)cin>>B[i];
int *c=Somma_Array(A,B,n);
for(int i=0;i<n*2;i++)cout<<c[i];
}
int* Somma_Array(int v[],int p[],int size)
{
int r[size*2];
for(int i=0;i<size;i++)r[i]=v[i];
for(int i=0;i<size;i++)r[i+size]=p[i];
return r;
}
it prints weird numbers instead of the actual number. I tried to do what this question says but it does not work. It gives me the following warning:
[Warning] address of local variable 'r' returned [enabled by default]
I'm using bloodshed dev-c++.
You define a stack allocated array r, which is destroyed when you exit the function Soma_Array. This is one of the (many) reasons vectors are preferred to plain arrays - they handle allocation and deallocation for you.
#include <vector>
std::vector<int> getArray()
{
std::vector<int> a = {1, 2, 3};
return a;
}
The following:
int r[size*2];
defines r locally. When the function exits (as in the scope of the function expires), r will be destroyed since it is bound to the function's scope. You are likely seeing junk data from the stack frame.
you could fix this by doing the following:
int* r = new int[size * 2];
The variable r will now be heap allocated and exist beyond the scope of the function.
IMPORTANT by doing this, you now must manually free r when you are done with it. So for instance, your calling code will look something like this:
int* result = Somma_Array(v, p, size);
/* ... do stuff ... */
delete[] result;
Since r is an array, note the use of delete[] instead of delete. delete[] is the correct way to destroy arrays.
A Better Alternative
Would std::vector be more what you are after? This is a much safer alternative to hand-rolled arrays. The vector is safer to use, scales automatically as you add elements, and cleans itself up nicely when it leaves scope (assuming you are using a value-type instance). Additionally, vectors can be copied and moved out of functions easily.
You cannot return arrays in C++. Especially, you should not return a pointer to a local array. You can however return a std::vector<int>:
std::vector<int> Somma_Array(int v[], int p[], int size)
{
std::vector<int> r(2 * size);
std::copy(v, v + size, r.begin());
std::copy(p, p + size, r.begin() + size);
return r;
}

Strange error regarding STL vector of pointers

I've a small code snippet which produces an error on running. The following code stores data of mystruct and creates a vector of pointers which store the addresses of the corresponding data.
struct mystruct{
std::vector < int > someinfo;
int somenumbers;
double *somepointer;
double someparm;
void Print(){....}
};
void DoSomething(mystruct &_somestruct, std::vector< mystruct > &_somevec,
std::vector<mystruct *> &_ptr){
_somevec.push_back(_somestruct);
_ptr.push_back(&(_somevec.back()));
}
void ReadStruct(){
std::vector<mystruct > _vec;
std::vector<mystruct *> _ptr;
for(int i=0;i<100;i++){
mystruct _struct;
_struct.somenumbers = 3;
_struct.someinfo.push_back(0);
_struct.someinfo.push_back(1);
_struct.someinfo.push_back(2);
DoSomething(_struct, _vec, _ptr);
}
_vec[0].Print(); //Prints correctly
_ptr[0]->Print();//Prints garbage info
}
If I first create the vector and then create the vector of pointers then the code works perfectly i.e.
void DoSomething(mystruct &_somestruct, std::vector< mystruct > &_somevec){
_somevec.push_back(_somestruct);
//_ptr.push_back(&(_somevec.back()));
}
void DoSomething1(std::vector< mystruct > &_somevec, std::vector<mystruct *> &_ptr){
for(int i=0;i<_somevec.size();i++)
_ptr.push_back(&(_somevec[i]));
}
I do not know what mistake I am doing. Your help/inputs is greatly appreciated!!
This does not look very safe to me.
In _ptr.push_back(&(_somevec.back())); you are taking the address of an element in _somevec. But when _somevec is changed by e.g. a push_back the address will be invalid!
For example this will not work:
std::vector<int> v;
v.push_back(17);
int* p = &v.back(); // pointer is valid
for(int i=0; i<10; i++) v.push_back(0);
*p = 42; // ERROR: p is no longer valid!
You can make this a bit better by using reserve prior to using push_back.
std::vector<int> v;
v.reserve(100); // v will now have enough room to not reallocate memory
v.push_back(17);
int* p = &v.back(); // pointer is valid
for(int i=0; i<10; i++) v.push_back(0);
*p = 42; // (probably) OK: p is still valid
But I would not recommend to do this.
It looks as if you are inserting elements into one vector and reference them with pointers from another vector. However, there doesn't seem to be any precaution against the vector of objects running out of capacity and relocating the objects, invalidating all the pointer.
The easiest approach to verify this hypothesis is to see if the capacity() of the vector of objects ever changes. The easiest fix is probably to use a std::deque<mystruct> as a std::deque<T> doesn't relocate its objects when adding/removing objects at either end.

unique_ptr pointing always to the same memory area

Consider this code:
using namespace std;
int* get()
{
unique_ptr<int> p (new int[4]);
return p.get();
}
int main(int argc, char **argv)
{
int *arr1=get();
int* arr2=get();
for(int i=0;i<4;i++)
{
arr1[i]=i;
arr2[i]=i*2;
}
for(int i=0;i<4;i++)
cout << arr1[i];
return 0;
}
arr1 and arr2 point to the same area of memory.
So they share the same values.
I don't understand why, when I call arr2=get() :
unique_ptr<int> p (new int[4]);
This object shouldn't be created again? It isn't deleted because still reachable by arr1.
How to get two arrays of different memory areas?
I am fairly sure you are playing with undefined behavior which is bad.
the data being pointed to was destroyed when the unique pointer was destroyed, the fact the values are the same, and the same slot was chosen is luck.
for pointers to array type use a vector
std::vector<int> get()
{
return std::vector<int>(4);
}
int main()
{
std::vector<int> arr1=get();
std::vector<int> arr2=get();
return 0;
}
for normal single value pointers then you can return a unique_ptr;
std::unique_ptr<int> get(){
return std::unique_ptr<int>(new int(0));
}
:::
std::unique_ptr<int> ptr=get();
There are a memory leak in such kind of usage of smart pointers. unique_ptr will use operator delete in order to free the allocated memory, but you need delete []. Also the return value of get function will be an invalid ptr because the unique_ptr will free the allocated area. If you need dynamically allocated arrays then use std::vector.