I'm working through the Stroustrup C++ 11 book, and I ran into a double free exception. I understand that it's freeing the memory twice, but what I don't understand is why it's happening for a function that's passing by copy:
#include <iostream>
using namespace std;
namespace ALL_Vector {
class Vector {
public:
// Intitialize elem and sz before the actual function
Vector(int size) :elem {new double[size]}, sz {size} {};
~Vector() {delete[] elem;};
double& operator[](int i) {
return elem[i];
};
int size() {return sz;};
private:
double* elem;
int sz;
};
void print_product(Vector& y) {
double result {1};
for (auto x = 0; x < y.size() ; x++){
if (y[x] > 0) {result *= y[x]; };
}
cout << "The product of Vector y is: " << result << ", or so it would appear ;)\n";
}
}
/*
Self test of the Vector class.
*/
int main(){
ALL_Vector::Vector myVector(15);
cout << "The size of Vector y is: " << myVector.size() << "\n";
myVector[0] = 12;
myVector[2] = 7;
myVector[3] = 19;
myVector[4] = 2;
ALL_Vector::print_product(myVector);
return 0;
}
print_product() is taking the Vector class and creating a new Vector with duplicated contents? Why would this cause a double free? I'm assuming that RIIA in this instance is somehow interacting with the Vector::~Vector(), something like a race condition?
I know if I change this to pass it's argument by reference it will avoid the double free. I'm trying to better understand the issue with passing by copy.
Thanks!
Actually you are calling print_product with a reference to myVector, so everything is fine.
Troubles begin with passing myVector by value because default copy constructor will copy elem pointer instead of duplicating the whole array.
Both ALL_Vector::Vector elem pointer will refer to same memory storage and thus be deleted twice.
To tackle this issue, you have to implement copy constructor to create a new array and copy all elements.
If you pass Vector per value, the copy constructor is called, not the constructor you have implemented.
In this case, elem is not duplicated but the pointer is copied in the new object and then deleted twice by the destructor.
You have to implement a copy constructor that allocate a new elem and copy all elements.
Related
How to delete the array of dynamic objects created in this following snippet?
I tried to go through some previous answers in the forum, but none could point answer for me.
#include <iostream>
struct Card{int x;};
int main()
{
std::vector<Card*> S;
for (int i = 0; i < 3; i++)
{
Card* o = new Card;
o->x = i;
S.push_back(o);
}
for (auto a : S)
std::cout << "Opening from the container " << a->x << '\n';
//delete o; --------> How to delete the array of objects???
return 0;
}
By looping through the vector and calling delete:
for(auto& elem : S)
{
delete elem;
}
Also, It's a good habit to range-loop over a container using (const) auto& instead of auto to prevent copies.
Also also, since you're using range-based for loops that means you have access to smart pointers so in reality you shouldn't be calling delete at all nor storing raw pointers.
Either store actual objects in the vector or store smart pointers like std::unique_ptr.
I'm passing an array to a constructor. Constructor has two parameters, pointer to int called data and int which is size of an array.
I'm allocation dynamic memory in constructor definition for this array and passing array pointer to this storage.
Last but one step is printing values in array through the pointer which is pointing to the first int value of this array.
The last step is freeing up memory in destructor delete [] data. In this step I got an error message: Debug Assertion Failed! Expression: _CrtlsValidHeapPpinter(block).
I'm very new in C++ so I'm struggling what I did wrong in below program. Could you give me a hint, please?
#include <iostream>
class Test
{
private:
int* data;
int size;
public:
// constructor and destructor
Test(int* d, int s);
~Test();
// few void methods
void display_data(int size)
{
for (int i{ 0 }; i < size; ++i)
{
std::cout << data[i] << " ";
}
std::cout << std::endl;
}
};
Test::Test(int* d, int s)
: data{nullptr}, size(s)
{
data = new int[s];
data = d;
}
Test::~Test()
{
std::cout << "Destructor is freeing memory" << std::endl;
delete[] data;
}
int main()
{
int data_array[5]{ 2,8,6,10,20 };
Test* t1 = new Test(data_array, 5);
t1->display_data(5);
delete t1;
return 0;
}
In yout Test::Test constructor you don't copy the array, you just copy the pointer. You need to use std::copy or memcpy (C-style) to copy the contents of d into data.
However, I would recommend to use STL containers (i.e., std::vector) instead of raw pointers. It will allow you to get rid of manual resource management (new/delete), which is error-prone and redundant.
You need to copy the data here. Instead of :
data = new int[s];
data = d;
Which creates an array and then forgets about it. This would lead to the array being deleted multiple times!
Copy the content of your array:
std::copy(d, d+s, data);
Or even better, use std::vector.
I'm trying to implement a dynamic array in c++. once it becomes full, its size is doubled and is copied to the double-sized array.
it looks fine but Valgrind says I have a leak.
I should say that I'm not allowed to use any of c++ STL structures- that's why I'm using new[] and delete[] operators.
this is my code:
template<class T>
class DynamicArray
{
int size;
int numOfElements;
T* arr;
public:
DynamicArray(int size) :
size(size), numOfElements(0)
{
arr = new T[size];
}
;
int getSize()
{
return size;
}
int getNumberOfElements()
{
return numOfElements;
}
void insert(T element)
{
arr[numOfElements++] = element;
if (numOfElements == size)
{
T* extended_array = new T[size * 2];
for (int i = 0; i < numOfElements; i++)
{
extended_array[i] = arr[i];
}
delete[] arr;
arr = extended_array;
size = size * 2;
}
}
T& operator[](int i)
{
if (!((i >= 0) && (i < size)))
throw arrayOutOfBoundsException();
return arr[i];
}
~DynamicArray()
{
delete[] arr;
}
class arrayOutOfBoundsException: std::exception
{
};
};
My main program is:
using std::cout;
using std::endl;
void printIntArray(DynamicArray<int> arr){
cout << "size: " << arr.getSize() << "; " << "numOfElemnts: " << arr.getNumberOfElements() << endl;
cout << "array: ";
for(int i=0; i<arr.getNumberOfElements(); i++){
cout << " " << arr[i];
}
cout << endl << endl;
}
int main() {
DynamicArray<int> arr(5);
printIntArray(arr);
arr.insert(1);
arr.insert(2);
arr.insert(3);
printIntArray(arr);
arr.insert(4);
printIntArray(arr);
arr.insert(5);
printIntArray(arr);
arr.insert(6);
printIntArray(arr);
arr.insert(7);
arr.insert(8);
arr.insert(9);
printIntArray(arr);
arr.insert(16);
printIntArray(arr);
arr[9] = 901;
arr[0] = 101;
printIntArray(arr);
**valgrind shows me this error- when the destructor is compiled as comment:
==3954== 80 bytes in 1 blocks are definitely lost in loss record 1 of 1
==3954== at 0x4A07192: operator new[](unsigned long) (vg_replace_malloc.c:363)
==3954== by 0x40103E: DynamicArray<int>::insert(int) (DynamicArray.h:41)
==3954== by 0x400DBC: main (main.cpp:44)**
Can anybody tell me what I was doing wrong? am I misusing "delete[]"? or the destructor?
thanks
The behaviour described by the asker is impossible or
when the destructor is compiled as comment:
means the destructor has been commented out and this is causing the leak. This has been confirmed in a comment. Without the destuctor the last allocation will never be put away.
The Asker's real problem is a Rule of Three Violation.
The short version goes something like this:
If a class requires a user defined copy constructor, assignment operator, or destructor it almost always requires all three.
More on that here: What is The Rule of Three?
In this case,
void printIntArray(DynamicArray<int> arr)
accepts arr by value. This means arr is a copy of the value passed in. In the absence of a custom copy constructor the arr inside printIntArray will point to the same allocation as the source. The copy will be destroyed at the end of printIntArray, and the destructor will delete the allocation, leaving the source pointing to invalid memory so...
DynamicArray<int> arr(5); // allocated storage inside arr
printIntArray(arr); // made a copy of arr that points to same storage.
// Storage freed when copy destroyed
arr.insert(1); // invokes undefined behaviour writing into invalid memory
arr.insert(2); // same
arr.insert(3); // same
printIntArray(arr); // copies arr again. This copy is pointing to the same invalid memory
// and will try to free the allocation a second time when the
// copy is destroyed
The program will almost certainly crash here, making it impossible to leak from the users code. But because the program crashed, Crom only knows what behind-the-scenes structures the runtime was using were not correctly put away.
Whatever happened, as of
arr.insert(1);
the program was deep in Undefined Behaviour and whatever happens after that is anybody's guess. Memory leaks are the least of your worries.
Fixing: Satisfy the Rule of Three
Implement a copy constructor and an assignment operator (We'll ignore the Rule of Five for now.)
You could change
void printIntArray(DynamicArray<int> arr)
to pass by reference
void printIntArray(DynamicArray<int> & arr)
and then
DynamicArray(const DynamicArray &) = delete;
DynamicArray& operator=(const DynamicArray &) = delete;
and disable all copying, but this seems a bit draconian.
Instead lets use Copy and Swap because it's simple and easy to understand. Note that it can also be inefficient, so it's not always the right tool. Here it fits what we want.
DynamicArray(const DynamicArray & src) :
size(src.size), numOfElements(src.numOfElements), arr(new T[size])
{
for (int i = 0; i < numOfElements; i++)
{
arr[i] = src.arr[i];
}
}
DynamicArray& operator=(const DynamicArray src)
{
std::swap(size, src.size);
std::swap(numOfElements, src.numOfElements);
std::swap(arr, src.arr);
return *this;
}
And because who wants to copy they don't need to we'll still
void printIntArray(DynamicArray<int> & arr)
as soon as we're done testing that the copy constructor works correctly.
I am using a derived class and a vector of pointers to objects from said class. I'm having some problems implementing copy constructors etc, even after reading a lot about it. I'm using c++11.
I have a loop where new objects of the derived class are created, and I then want to put these into the vector. But since it is a vector of pointers I must put the address of the created object there instead.
I believe my problems stem from this fact, together with objects going out of scope etc and my not being able to implement copy constructors / copy assignment constructors etc in a satisfactory way.
I've made a minimal example that I think illustrates my problem. Let's say the initial setup is as follows (I know it doesn't make much sense, e.g. with the pointer *n, but I think this shows the issues with my actual code):
using namespace std;
#include <iostream>
#include <vector>
class Base {
protected:
int* n;
public:
void display(string name="") {cout << name << "n = " << *n << endl;}
Base() {}
Base(int n_) {
*n=n_;
cout << "Initialised to " << *n << endl;
}
};
class Derived : public Base {
public:
Derived() : Base() {}
Derived(int n_) : Base(n_) {}
};
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
Derived tmp(i);
tmp.display("Tmp: ");
list.push_back(&tmp);
}
cout << endl;
for(int i=0;i<list.size();i++) {
cout << "Address of " << i << ": " << list[i] << endl;
list[i]->display("Element "+to_string(i)+" : ");
}
}
The output of this is:
Initialised to 0
Tmp: n = 0
Initialised to 1
Tmp: n = 1
Initialised to 2
Tmp: n = 2
Initialised to 3
Tmp: n = 3
Initialised to 4
Tmp: n = 4
Address of 0: 0x7fff3a1df2d0
Element 0 : n = 0
Address of 1: 0x7fff3a1df2d0
Element 1 : n = 0
Address of 2: 0x7fff3a1df2d0
Element 2 : n = 0
Address of 3: 0x7fff3a1df2d0
Element 3 : n = 0
Address of 4: 0x7fff3a1df2d0
Element 4 : n = 0
So after the loop all the elements in the list point to the same address, where n=0 (probably undefined behaviour from tmp going out of scope).
So rather than just putting the address of tmp into list I'm thinking I somehow have to make instances of Derived that survive the loop while still just having addresses in list.
As mentioned I've tried doing this using various special member functions with no luck.
Note that it might seem implementing a vector of the objects themselves might be easier, but that leads to other problems in my actual code. If I can't get this working I'll try that instead though.
It has nothing to do with with copying or copy-constructors, it is simply only because the objects go out of scope and gets destructed, while you still keep a pointer to these (now destructed) objects. This leads to undefined behavior when you try to dereference these pointers.
Instead you need to dynamically allocate these objects, using e.g. new. You could wrap these pointers using C++11 smart pointers.
You add pointers to objects on the stack to your vector. When the current scope ends, these objects will be destroyed, but the pointer is still there.
You'll have to create new objects instead.
int main(int argc, const char* argv[]) {
vector<Base*> list;
for(int i=0;i<5;i++) {
auto tmp = new Derived{i};
tmp->display("Tmp: ");
list.push_back(tmp);
}
// ...
}
}
Now you still have to make sure, you free the objects as needed. Whenever possible prefer to resort to unique_ptr<> or shared_ptr<>:
int main(int argc, const char* argv[]) {
vector<unique_ptr<Base>> list;
for(int i=0;i<5;i++) {
auto tmp = make_unique<Derived>(i);
tmp->display("Tmp: ");
// this should move the unique_ptr and therefore transfer
// its ownership to the vector.
list.emplace_back(tmp);
}
// ...
}
}
Now the objects will be destroyed, either when they are removed from the vector, or when the vector is destroyed. With shared_ptr that might be delayed, untill no part of your programm holds any shared_ptr<> to the same object.
If I have a list<object*>>* queue and want to pop the first object in the list and hand it over to another part of the program, is it correct to use (sketchy code):
object* objPtr = queue->first();
queue->pop_first();
return objPtr; // is this a pointer to a valid memory address now?
?
According to the documentation on http://www.cplusplus.com/reference/stl/list/pop_front/ it calls the destructor of the deleted element, but I'm confused as to whether it means the linked list's node object, or the actually stored "user" object.
Edit: I might be front instead of first, my bad.
Yes, it is a valid pointer. List will not release the memory allocated by you. List will destroy its internal not the user object.
Yes it's valid: Since you put pointers into the list, only the pointer gets destroyed, not the object itself.
Yes objPtr contains pointer to a valid memory.
When you insert an element into a std::list, list makes a copy of it. In your case the element is an address (a pointer) so list makes a copy of the address and stores it.
object * optr = queue->pop_front();
optr now points to the object
queue->pop_front();
removes the element (an address/pointer) from the list, optr already points to your object.
After you're done with the object don't forget do delete it otherwise you end up with memory leak.
Example:
#include <iostream>
#include <list>
using namespace std;
struct A
{
static int count;
A() : val(count++) { cout << "A(" << val << ")" << endl; }
~A() { cout << "~A(" << val << ")" << endl; }
int val;
};
int A::count = 0;
ostream& operator<<(ostream& os, A& a) { return os << a.val; }
int main()
{
list<A*> alist;
for (unsigned int i = 3; i; --i) alist.push_back(new A());
for (unsigned int i = 3; i; --i)
{
A * aptr = alist.front();
alist.pop_front();
cout << *aptr << endl;
delete aptr;
aptr = 0;
}
}
The standard indeed says (23.2.2.3/5) that the destructor of the element's type is called. But this type is a pointer here, and the destructor of a pointer does nothing...
Your code is well but it is better to use list< boost::shared_ptr<object> >.
shared_ptr < object> objPtr = queue->first();
queue->pop_first();
return objPtr;
When you remove the elements, STL containers will not destroy the user objects allocated on heap.
class A
{
};
list<A*> PointerToObjectList;
A* ptr = new A();
PointerToObjectList.push_back(ptr);
If you remove the ptr from the list, list will not delete the object automatically. You need to explicitly call delete once the object is no longer being used.