When does the object Second go out of scope? If I leave the third cout statement I get a compiler error. Even when I surround the initialization of Second and the cout statements.
#include <iostream>
using namespace std;
class MyArray{
public:
int Size;
int* data;
MyArray(int s) : Size(s), data(new int[s]){}
~MyArray(){
delete[](this->data);
}
};
int main()
{
MyArray First(20);
First.data[0] = 25;
MyArray Second = First;
cout << First.data[0] << endl;
cout << Second.data[0] << endl;
cout << Second.data[0] << endl;
system("PAUSE");
return 0;
}
The runtime error:
Here is what's going on: MyArray objects get a pointer to their own array of integers called data upon initialization. However, this line changes things for the Second object:
MyArray Second = First;
Now both First.data and Second.data point to the same int[] array, because the default copy constructor and assignment operator perform a shallow copy.
This is bad, because the compiler has freedom to destroy First after its last use in your code. Hence, accessing Second.data[0] may be invalid already.
Moreover, once First and Second go out of scope at the end of main(), they both will try deleting data. Only the first one would succeed; the second one will trigger undefined behavior.
To avoid such errors in the future, use the rule of three. It says that if you define a destructor, a copy constructor, or an assignment operator, you probably need all three of them.
Your code has only the destructor. Adding a copy constructor and an assignment operator will fix this problem, and prevent memory leaks on assigning MyArray objects.
The scope of both names ends at the }. (Scope is a compile-time notion.)
The lifetime of Second ends when execution reaches the end of the block, after which the lifetime of First ends. But your program has undefined behaviour because you delete the array twice, so anything can happen.
You need to do the deep copy using copy constructor
MyArray(const MyArray &t)
{
t.size = size;
if(size not_eq 0)
{
t.data = new int(size);
for(int i=0 ; i<size ; i++)
t.data[i] = data[i];
}
}
after this MyArray Second = First; will work fine
if you want to assign then you have to write assignment operator as well
Related
EDIT: I had to use unique_ptr or follow the rule-of-five I'm still learning about it so I used unique_ptr and it worked. But I have a question, the destructor now is being called twice and I think that is no problem as long as the block of memory that the pointer is pointing to is not being freed twice, Right??
I made a simple "String" class in c++ (Know it from The Cherno). So I made it and it seems to work well until I decided to add an empty constructor to be able to initialize it with no parameter but when I did that the destructor is being called twice.
// here is the header file
#pragma once
#include <iostream>
using namespace std;
class String
{
private:
//Hold the raw of chars in the heap memory
char* m_Buffer;
//The size of the buffer in heap
unsigned int m_Size;
public:
//An empty Constructor
String()
: m_Buffer(nullptr), m_Size(0)
{
cout << "created Empty." << endl;
}
// A Constructor
String(const char* string)
{
m_Size = strlen(string);
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, string, m_Size + 1);
m_Buffer[m_Size] = 0;
}
// A destructor
~String()
{
cout << "Destroy!!" << endl;
delete[] m_Buffer;
}
// Function resposable for coping
String(const String& other)
: m_Size(other.m_Size)
{
m_Buffer = new char[m_Size + 1];
memcpy(m_Buffer, other.m_Buffer, m_Size + 1);
}
char& operator[](unsigned int& index)
{
return m_Buffer[index];
}
friend std::ostream& operator<<(std::ostream& stream, const String& other);
};
std::ostream& operator<<(std::ostream& stream, const String& other)
{
stream << other.m_Buffer << endl;
return stream;
}
//here is the main file
#include "LclString.h"
int main()
{
String a = "asdc";
a = "ads"; // The Destructor is being called here the first time
cin.get();
} // and here is the second time
A piece of advice will be appreciated
......................................
Your destructor calls delete[] m_Buffer. A pointer may never be deleted twice. If you do delete a pointer twice, then the behaviour of the program will be undefined. You must avoid ever doing that. To achieve avoiding that, you must make sure that no two instances of the class have the same pointer value in the member.
Consider what the implicitly generated assignment operator of your class does. It copies all members from the right hand operand to the left hand operand. Can you see why that is a problem? All members include the m_Buffer pointer. The assignment operator will cause two instances of the class to have the same pointer. And when the second instance is destroyed, it deletes that same pointer again. And the behaviour of the program is undefined.
There is another related problem, the implicit assignment operator overwrites the old m_Buffer. Who's going to delete the pointer that was overwritten? No-one is going to delete it because the value was lost by the assignment. That's a memory leak.
Conclusion:
Avoid using owning bare pointers.
Avoid using new and delete directly.
If you have a user defined destructor, then you probalby also need user defined copy/move constructor and assignment operator. This is known as rule of 5 (previously rule of 3). If you use smart pointers instead of owning bare pointers, then you usually don't need a user defined destructor.
I am a bit confused with the way vector push_back behaves, with the following snippet I expected the copy constructor to be invoked only twice, but the output suggest otherwise. Is it a vector internal restructuring that results in this behaviour.
Output:
Inside default
Inside copy with my_int = 0
Inside copy with my_int = 0
Inside copy with my_int = 1
class Myint
{
private:
int my_int;
public:
Myint() : my_int(0)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
void set(const int &x)
{
my_int = x;
}
}
vector<Myint> myints;
Myint x;
myints.push_back(x);
x.set(1);
myints.push_back(x);
What happens:
x is inserted via push_back. One copy occurs: The newly created element is initialized with the argument. my_int is taken over as zero because xs default constructor initialized it so.
The second element is push_back'd; The vector needs to reallocate the memory since the internal capacity was reached. As no move constructor is implicitly defined for Myint1 the copy constructor is chosen; The first element is copied into the newly allocated memory (its my_int is still zero... so the copy constructor shows my_int as 0 again) and then x is copied to initialize the second element (as with the first in step 1.). This time x has my_int set to one and that's what the output of the copy constructor tells us.
So the total amount of calls is three. This might vary from one implementation to another as the initial capacity might be different. However, two calls are be the minimum.
You can reduce the amount of copies by, in advance, reserving more memory - i.e. higher the vectors capacity so the reallocation becomes unnecessary:
myints.reserve(2); // Now two elements can be inserted without reallocation.
Furthermore you can elide the copies when inserting as follows:
myints.emplace_back(0);
This "emplaces" a new element - emplace_back is a variadic template and can therefore take an arbitrary amount of arguments which it then forwards - without copies or moves - to the elements constructor.
1 Because there is a user-declared copy constructor.
You got it...it was the resizing. But I'll just point out that if you're doing some bean counting on your constructors, you might be interested in "emplacement":
#include <iostream>
#include <vector>
using namespace std;
class Myint
{
private:
int my_int;
public:
explicit Myint(int value = 0) : my_int(value)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
Myint(const Myint&& x) noexcept : my_int(x.my_int) {
cout << "Inside move with my_int = " << x.my_int << endl;
}
};
int main() {
vector<Myint> myints;
myints.reserve(2);
myints.emplace_back(0);
myints.emplace_back(1);
// your code goes here
return 0;
}
That should give you:
Inside default
Inside default
And, due to the noexcept on the move constructor...if you delete the reserve you'd get a move, not a copy:
Inside default
Inside default
Inside move with my_int = 0
There's no real advantage with this datatype of a move over a copy. But semantically it could be a big difference if your data type was more "heavy weight" and had a way of "moving" its members that was more like transferring ownership of some pointer to a large data structure.
When the size of the vector is increased with the second push_back, the existing contents of the vector must be copied to a new buffer. To verify, output myints.capacity() after the first push_back, it should be 1.
This depends on how much memory was reserved to an object of type std::vector. It seems that when push_back was first executed there was allocated memory only for one element. When the second time push_back was called the memory was reallocated to reserve memory for the second element. In this case the element that is already in the vector is copied in the new place. And then the second element is also added.
You could reserve enough memory yourself that to escape the second call of the copy constructor:
vector<Myint> myints;
myints.reserve( 2 );
You're correct in assuming the additional invocation of the copy constructor comes from internal restructuring of the vector.
See this answer for more detail: https://stackoverflow.com/a/10368636/3708904
Or this answer for the reason why copy construction is necessary: https://stackoverflow.com/a/11166959/3708904
I am a student so I apologize up front for not using the correct forum protocols. I have searched for hours on this problem, none of my classmates can help. My assignment is to create a copy constructor, overloaded assignment operator(=) and a destructor (the 'big three') in C++ to manage an array on the heap. What I wrote below in VS13 produces the correct output but I get a debug error: HEAP CORRUPTION DETECTED:c++ crt detected that the application wrote to memory after end of heap buffer
Can anyone give me some guidance on this, I don't even know where to look. Thanks!!
//copy constructor
myList::myList(const myList& source){
cout << "Invoking copy constructor." << endl;
array_capacity = source.array_capacity; //shallow copy
elements = source.elements; //shallow copy
delete[] arrayPointer;
arrayPointer = new double(source.array_capacity); //deep copy
for (int i = 0; i < array_capacity; i++) //copy array contents
{
arrayPointer[i] = source.arrayPointer[i];
}
}
//overloaded assignment operator
myList& myList::operator=(const myList& source){
cout << "Invoking overloaded assignment." << endl;
if (this != &source){
array_capacity = source.array_capacity; //shallow copy
elements = source.elements; //shallow copy
delete[] arrayPointer; //delete original array from heap
arrayPointer = new double(array_capacity); //deep copy
for (int i = 0; i < source.array_capacity; i++) {//copy array contents
arrayPointer[i] = source.arrayPointer[i];
}
}
return *this;
}
//destructor
myList::~myList(){
cout << "Destructor invoked."<< endl;
delete[] arrayPointer; // When done, free memory pointed to by myPointer.
arrayPointer = NULL; // Clear myPointer to prevent using invalid memory reference.
}
There are a couple of problems with your code. First you are invoking delete on arrayPointer but it hasn't been initialized to anything. This could in fact end up deleting memory you have already allocated or result in an excecption or asset in the implementation of delete. Second when you do initialize it you are allocating a single double initialized to the value of source.array_capacity. Notice the parenthesis used in the line below.
arrayPointer = new double(source.array_capacity);
This will certainly result in undefined behavior during the copy as you end up accessing elements outside the bounds of the array. The above line is present in both your copy constructor and copy-assignment operator and should be using square brackets instead like so:
arrayPointer = new double[source.array_capacity];
You also never check to see if there are any elements stored in the source instance of myList. In this case you should likely be assigning nullptr (or NULL in C++03) to arrayPointer.
As a side note you do not really need to assign NULL to arrayPointer in your destructor. Once the object is destroyed it's gone and any attempt to access it after the fact will result in undefined behavior anyway.
Captain Obvlious pointed out the problem in your copy-constructor already.
You will have noticed that the copy-constructor and the assignment-operator contain a lot of the same code but with a subtle difference. In fact this is probably how you ended up with the error (the assignment operator needs to delete[] the old value, but the copy-constructor doesn't.
Code duplication is bad because it leads to subtle errors like this creeping in. A good pattern you can use here is what's called the copy and swap idiom.
The gist is that you define the copy-constructor, and you also define swap. Then you get assignment for free. This works because swap is easier to implement correctly than the assignment operator, and another major benefit is that nothing can go wrong (you don't have to worry about out-of-memory errors and so on).
In your code; keeping your fixed copy-constructor, you could add inside the class definition:
friend void swap( myList &a, myList &b )
{
std::swap( a.array_capacity, b.array_capacity );
std::swap( a.arrayPointer, b.arrayPointer );
std::swap( a.elements, b.elements );
}
and now the assignment operator is very simple:
myList& myList::operator=(const myList &source)
{
myList temp(source);
swap(*this, temp);
return *this;
}
The old resources from the current object are deleted by the destructor of temp. This version doesn't even need to check for self-assignment because std::swap(x, x) is well-defined.
This can even be optimized further by taking source by value instead of by reference, as explained on the linked page.
I am a bit confused with the way vector push_back behaves, with the following snippet I expected the copy constructor to be invoked only twice, but the output suggest otherwise. Is it a vector internal restructuring that results in this behaviour.
Output:
Inside default
Inside copy with my_int = 0
Inside copy with my_int = 0
Inside copy with my_int = 1
class Myint
{
private:
int my_int;
public:
Myint() : my_int(0)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
void set(const int &x)
{
my_int = x;
}
}
vector<Myint> myints;
Myint x;
myints.push_back(x);
x.set(1);
myints.push_back(x);
What happens:
x is inserted via push_back. One copy occurs: The newly created element is initialized with the argument. my_int is taken over as zero because xs default constructor initialized it so.
The second element is push_back'd; The vector needs to reallocate the memory since the internal capacity was reached. As no move constructor is implicitly defined for Myint1 the copy constructor is chosen; The first element is copied into the newly allocated memory (its my_int is still zero... so the copy constructor shows my_int as 0 again) and then x is copied to initialize the second element (as with the first in step 1.). This time x has my_int set to one and that's what the output of the copy constructor tells us.
So the total amount of calls is three. This might vary from one implementation to another as the initial capacity might be different. However, two calls are be the minimum.
You can reduce the amount of copies by, in advance, reserving more memory - i.e. higher the vectors capacity so the reallocation becomes unnecessary:
myints.reserve(2); // Now two elements can be inserted without reallocation.
Furthermore you can elide the copies when inserting as follows:
myints.emplace_back(0);
This "emplaces" a new element - emplace_back is a variadic template and can therefore take an arbitrary amount of arguments which it then forwards - without copies or moves - to the elements constructor.
1 Because there is a user-declared copy constructor.
You got it...it was the resizing. But I'll just point out that if you're doing some bean counting on your constructors, you might be interested in "emplacement":
#include <iostream>
#include <vector>
using namespace std;
class Myint
{
private:
int my_int;
public:
explicit Myint(int value = 0) : my_int(value)
{
cout << "Inside default " << endl;
}
Myint(const Myint& x) : my_int(x.my_int)
{
cout << "Inside copy with my_int = " << x.my_int << endl;
}
Myint(const Myint&& x) noexcept : my_int(x.my_int) {
cout << "Inside move with my_int = " << x.my_int << endl;
}
};
int main() {
vector<Myint> myints;
myints.reserve(2);
myints.emplace_back(0);
myints.emplace_back(1);
// your code goes here
return 0;
}
That should give you:
Inside default
Inside default
And, due to the noexcept on the move constructor...if you delete the reserve you'd get a move, not a copy:
Inside default
Inside default
Inside move with my_int = 0
There's no real advantage with this datatype of a move over a copy. But semantically it could be a big difference if your data type was more "heavy weight" and had a way of "moving" its members that was more like transferring ownership of some pointer to a large data structure.
When the size of the vector is increased with the second push_back, the existing contents of the vector must be copied to a new buffer. To verify, output myints.capacity() after the first push_back, it should be 1.
This depends on how much memory was reserved to an object of type std::vector. It seems that when push_back was first executed there was allocated memory only for one element. When the second time push_back was called the memory was reallocated to reserve memory for the second element. In this case the element that is already in the vector is copied in the new place. And then the second element is also added.
You could reserve enough memory yourself that to escape the second call of the copy constructor:
vector<Myint> myints;
myints.reserve( 2 );
You're correct in assuming the additional invocation of the copy constructor comes from internal restructuring of the vector.
See this answer for more detail: https://stackoverflow.com/a/10368636/3708904
Or this answer for the reason why copy construction is necessary: https://stackoverflow.com/a/11166959/3708904
Consider the following class:
class Stats
{
private:
int arraySize; // size of array
int * data; // pointer to data, an array of integers
// default size of array in default constructor
static const int DEFAULT_SIZE = 10;
public:
Stats() // default constructor
{
arraySize = DEFAULT_SIZE; // element count set to 10
data = new int[DEFAULT_SIZE]; // array of integers
srand((unsigned int) time(NULL)); // seeds rand() function
// initializes integer array data with random values
for (int i = 0; i < DEFAULT_SIZE; i++)
{
// data filled with value between 0 and 10
data[i] = rand() % (DEFAULT_SIZE + 1);
}
}
~Stats() // destructor that deletes data memory allocation
{
delete [] data;
}
void displaySampleSet(int numbersPerLine)
{
cout << "Array contents:" << endl; // user legibility
// iterates through array and prints values in array data
for (int i = 0; i < arraySize; i++)
{
cout << data[i];
/* nested if statements that either prints a comma between
values or skips to next line depending on value of numbersPerLine */
if (i + 1 < arraySize)
{
if ((i + 1) % numbersPerLine != 0)
cout << ", ";
else
cout << endl;
}
}
}
}
For some reason, when I create a Stats object in the following way:
Stats statObject = Stats();
and then call the displaySampleSet() on it, the numbers display fine. However, the function prints garbage when the Stats object is created in the following way:
Stats statObject;
statObject = Stats();
I have no idea why it does this and have a feeling it has to do with the integer pointer 'data' and/or with the way the object is being created but I'm not sure what... Any and all help is fully appreciated! Thank you so much in advance.
Update: Destructor added
Both the code statements produce undefined behavior. It is lucky that the first one works while second doesn't.
Stats statObject = Stats();
Is copy initialization. It copies the created Stats object by calling the default constructor and then copies it in to statObject by calling the copy constructor. Note your class does not provide an copy constructor so the implicitly generated one gets used. This creates a shallow copy of the dynamically allocated members. The object from which this copy gets created is eventually destroyed and then whats left in your class is dangling pointers which do not point to anything valid. The copy constructor needs to do a deep copy.
Same is the case with:
Stats statObject;
statObject = Stats();
Wherein the compiler generated copy assignment operator is called. Resulting in similar problems as in case 1.
You need to follow the Rule of Three and provide your copy constructor and copy assignment operators for the class.
You code is using synthesized copy constructor , assignment operator defined by compiler.
Also you are not freeing the memory allocated dynamically for default constructor.
you have to define your own copy construcor, overload assignment operator( follow rule of three).
Both the cases are undefined behaviour
Stats statObject;
statObject = Stats(); //using compiler defined assignment operator.
Stats statObject = Stats(); //using compiler defined copy constructor.
Here temp object generated is is using assignment operator overloaded by compiler and is doing shallow copy instead of deep copy.
overload assignment operator:
Stats& operator=(const Stats& rhs);
define copy constructor:
Stats(const Stats& rhs);