do I HAVE to use the new keyword? - c++

This isn't the code I'm working on but it's the gist of what I want to do.
object *objects; int totalObjects;
void addObject(object o)
{
objects[totalObjects] = o;
totalObjects++;
}
It's giving me an access error when I try this:
Unhandled exception at 0x00e8a214 in crow.exe: 0xC0000005: Access violation writing location 0xcccccccc
Am I going to have to use 'new' and if so do I have to create a new array to copy to every time? Can I just add or take elements from the array I'm using?

Why don't you just use std::vector?
std::vector<object> objects;
void addObject(object o)
{
objects.push_back(o);
}
..or
void addObject(const object &o)
{
objects.push_back(o);
}
to remove additional copying.
When it comes to implementing your own dynamic array without std::vector, Yes. you need to allocate new memory, and copy your array to new memory block. Here's my example code with malloc and placement new.
#include <stdlib.h> // for malloc/free
#include <new> // for placement new, std::bad_alloc
object *objects = nullptr;
size_t totalObjects = 0;
void addObject(const object &o)
{
object *old_objects = objects;
size_t old_size = totalObjects;
size_t new_size = totalObjects + 1;
object *new_objects = (object *)malloc(sizeof(object) * new_size);
if (new_objects == nullptr)
throw std::bad_alloc();
size_t i;
try
{
for (i = 0; i < old_size; ++i)
{
new (&new_objects[i]) object(old_objects[i]); // placement new
}
}
catch (...)
{
// destroy new_objects if an exception occurs during creating new_objects
for (size_t j = 0; j < i; ++j)
{
new_objects[i].~object();
}
free(new_objects);
throw;
}
objects = new_objects;
free(old_objects);
}
(I haven't tested the code yet >o<)
Note that I used malloc and placement new, not new operator. It's impossible to call copy constructor of each element of the dynamic array with array-new.
However, if your object is TriviallyCopyable, you can use realloc. It can be more efficient, because realloc can just expand memory block, without copying - if the memory is enough.
..And you can select multiple lines and just press TAB in Visual Studio (..or many other editors).

You declared an object pointer, but not yet allocated the actual memory to store object objects. Your assignment statement merely tries to copy the input object o into an unallocated array member.
This is why you should use new before the assignment. The new operator asks the system to allocate some memory in the required size, then return the address of that memory and assign it to the pointer. Then, the pointer points to that newly allocated memory and the assignment (or copying) can be made.
When you finished using the array space, you should free the allocated memory using delete.

Okay, I'm going to add an answer to my own question. Let me know if this is bad etiquette. I just wanted to post some of my own code to duel with yours.
#include <vector>
std::vector<object> objects;
okay so I want to have two arrays (vectors) for the objects and double for distances so I may end up with
std::vector<double> distances;
void swap(unsigned int a, unsigned int b)
{
objects.swap_ranges(a,b);
distances.swap_ranges(a,b)
}
I'm going by the cplusplus.com reference for this function so let me know if I have it wrong. I'm going to go through it and completely redo my code.
Is there a type like the matrix that will let me hold data of different types so I don't have to invent a new object to handle each one individually?
If what you wrote is the most efficient and fast way to do this then I'll make a new class to hold both items.
thanks :)

Related

Deleting dynamic array in C++ causes an error

I have a class called Myclass. In the main function, I have created an array object for this class. Whenever I try to delete this dynamically allocated array, the visual studio will say, Error: Debug Assertion Failed!. Expression: is_block_type_valid(header->_block_use). Can you please tell me what is causing this or show me an example of fixing this issue.
#include <iostream>
using namespace std;
class Myclass
{
public:
void print()
{
cout << "Hello from Myclass" << endl;
}
};
int main()
{
Myclass *obj[3] = { new Myclass, new Myclass, new Myclass };
// Call each object's print function.
for (int index=0; index < 3; index++)
{
obj[index]->print();
}
delete[] obj; //Error
return 0;
}
This:
Myclass *obj[3] = { new Myclass, new Myclass, new Myclass };
is not a dynamically allocated array. It is an array with automatic storage, holding pointers to dynamically allocated objects. To properly clean up, you need:
delete obj[0];
delete obj[1];
delete obj[2];
Because every new must be matched with a delete, and you can only delete via delete[] something that was allocated via new[].
There is no need for any dynamic allocation here, just do:
Myclass obj[3] = {};
The delete[] operator should only be used for arrays created using the new[] operator, which your obj isn't. You have a fixed array of pointers to objects, each of which must be deleted as such:
for (int index=0; index < 3; index++)
{
delete obj[index];
}
Alternatively, you can create your object array using the new[] operator, then delete the array with delete[]:
int main()
{
Myclass* obj = new Myclass[3];
// Call each object's print function.
for (int index = 0; index < 3; index++) {
obj[index].print(); // Note: Use "." here, not "->"
}
delete[] obj;
return 0;
}
The variable obj is declared as an array with automatic storage duration with the element type Myclass *.
Myclass *obj[3] = { new Myclass, new Myclass, new Myclass };
That is it is an array of pointers not a pointer.
Each element of the array is indeed a pointer that points to a dynamically allocated memory. So as the array contains three elements you need to call the operator delete three times for each element.
It is simpler to do that in the range-based for loop.
For example
for ( auto &item : obj )
{
delete item;
item = nullptr;
}
I think you allocated the array wrong.
You should write Myclass* obj = new Myclass[3];
The above answer is perfect.
I would only add this is not a good style code, if you "think in C++". This is a rather C style code.
First of all, when you are coding in C++ and is not obligued to use C-compatible code, be cautious whenever you see yourself using a C pointer.
In this case, if instead of using a C array of C pointers, you had used a std::vector of MyClass objects, the vector destructor would have called your class destructor for each element, which I think is what you wanted.
My suggestion: change the C array to std::vector and you will be happier. Look how you could have implemented it, using C++11 features and forgetting old C stuff:
#include <iostream>
using namespace std;
#include <vector>
class Myclass
{
public:
void print()
{
cout << "Hello from Myclass" << endl;
}
};
int main()
{
cout<<"Hello World" << endl;
vector<Myclass> obj(3);
// Call each object's print function.
for (auto instance : obj)
{
instance.print();
}
return 0;
}
In this case you don't even need to worry about deleting the objects, since the vector destructor will be called when the function goes out of scope, and it will take care of calling Myobjects' destructors. Much cleaner and safer code.
Or, in case performance is a very bottleneck for you and you need a static array, if you are using C++11 or later, you also can use std::array, a less "wild" option (https://en.cppreference.com/w/cpp/container/array).
So that is the tip I leave for you, if coding in C++, use the best this language can offer, and try to forget dangerous and wild old C features. C is good as a lightweight and simpler language, when you need it. But everyone knows it is dangerous (and you have just stumbled on it).
This book of the Bjarne focuses on teaching C++ from scratch, leaving behind the not always productive C legacy:
Programming: Principles and Practice Using C++

Is it bad practice to reinitialize a pointer?

I have an Image class and initially I do not know the image dimensions, so I just initialize a data_ pointer to be an array of size 0. Later when I find the image information I reinitialize data_ to a new size. Will this create any problem in memory? and is there a cleaner way to do this?
Below is the class I have written:
class Image
{
private:
int numRows_, numCols_;
unsigned char* data_;
public:
Image() : numRows_(0), numCols_(0), data_(new unsigned char[0])
{}
void setData(int r, int c, unsigned char* data)
{
this->numRows_ = r;
this->numCols_ = c;
this->data_ = new unsigned char[r*c];
for (int i = 0; i < r*c; i++)
{
this->data_[i] = data[i];
}
}
int rows();
int cols();
unsigned char* data();
~Image();
};
Thanks in advance
This will in fact leak memory. The call to new allocates memory for the array, even if it is empty. As soon as you reassign data_, the previous array is leaked and can no longer be freed.
You can either make sure you delete[] any new[] you allocate, or just don't allocate an empty array and instead set data_ to nullptr until you have meaningful data to use.
An even better idea is don't allow the creation of an object in an invalid state, require the data in the constructor - see RAII:
In RAII, holding a resource is a class invariant, and is tied to
object lifetime: resource allocation (or acquisition) is done during
object creation (specifically initialization), by the constructor,
while resource deallocation (release) is done during object
destruction (specifically finalization), by the destructor.
If you do decide to keep setData, then as mentioned in comments, you also must make sure to delete[] existing data in setData before reassigning data_, in case the method is called more than once.
I think a cleaner way to do so will be using a vector:
std::vector<unsigned char> v; // vector with size 0
v.resize(r*c); // after size is known, just resize

Where should I put delete statements in my code to remove the memory leak?

There is a memory leak that I see in Valgrind in my C++ program. I'm wondering where I should place delete statements to remote it. Thank you.
#include <iostream>
using namespace std;
void showFloatArray(float f1[10]) {
for (int i=0; i < 10; i++)
cout << " " << f1[i];
cout << endl;
}
float *getFloatArrayOne() {
float *floatArray = new float[10];
for (int i=0; i < 10; i++)
floatArray[i] = (float) i;
return(floatArray);
}
float *getFloatArrayTwo() {
float myFloatArray[10];
float *floatArray = myFloatArray;
for (int i=0; i < 10; i++)
floatArray[i] = (float) i;
return(floatArray);
}
int main()
{
float *f1 = getFloatArrayOne();
float *f2 = getFloatArrayTwo();
showFloatArray(f1);
showFloatArray(f2);
}
Anytime you create a pointer with new then you have to make sure you call delete on that pointer before the program ends.
For example:
int main()
{
Object * obj = new Object;
return 0; //leaky program!
}
int main()
{
Object * obj = new Object;
delete obj;
return 0; //non-leaky program!
}
Quick re-write
Better to get caller to make allocations. Caller then knows to allocate and de-allocate. If your function (eg a library) allocates, then caller might be in doubt about whether objects must be de-allocated.
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
// remove fixed size restriction on function
void print_array(float* f, size_t size) {
for (size_t i=0; i < size; i++)
cout << " " << f[i];
cout << endl;
}
// pass in array
float* getFloatArrayOne(float f[], size_t size) {
for (size_t i=0; i < size; i++)
f[i] = (float)i;
return f;
}
// pass in ptr - caller responsible for allocation and de-allocating
float *getFloatArrayTwo(float* f, size_t size) {
for (size_t i=0; i < size; i++)
*(f+i) = (float)i; // dereference pointer + offset method
return f;
}
// You can use any algorithm you like to generate numbers
struct myincrementer {
myincrementer(float startval) : n_(startval) {}
float operator()() { return ++n_; } // change to n_++ to start printing first value
float n_;
};
int main()
{
const int size = 10;
float* floatArray = new float[size]();
float *f1 = getFloatArrayOne(floatArray, size);
float myFloatArray[size] = {0};
float *f2 = getFloatArrayTwo(myFloatArray, size);
print_array(f1, size);
print_array(f2, size);
delete [] floatArray; // note [] form
// More advanced approach
vector<float> vec;
myincrementer myi(0.0);
generate_n(back_inserter(vec), 10, myi);
std::copy(vec.begin(), vec.end(), std::ostream_iterator<float>(std::cout, " "));
}
'Modern' C++ typically avoids leaks by not using new and delete directly, instead delegating the management of resources like memory to objects that handle them internally.
However since this is homework it seems worthwhile to learn not just good practices which eliminate problems, but the technical details of what a leak is and the formal requirements to avoid a leak, independent of any particular method for effectively carrying out those requirements.
So here it is: A memory leak occurs when a pointer value is returned by a successful call to an allocation function and no subsequent call to the correct deallocation function is made using the value returned by the allocation function. That is, a leak occurs when you allocate memory and then fail to deallocate it.
Allocations by malloc() must be deallocated with free(). Allocations by new must be deallocated with delete. Allocations by new[] must be deallocated with delete[].
int *x = malloc(sizeof(int)); // C code
if (x) {
// allocation succeeded, you can use the resource and you should free() it
// ... use
free(x);
}
int *y = new int;
delete y;
int *z = new int[10];
delete [] z;
In Practice
So fixing or avoiding memory leaks requires 'merely' that your program call the deallocation function for every successful allocation. The challenge however, is that this is difficult to do in an arbitrary or ad-hoc manner. In order to avoid leaks in practice you need to establish patterns of allocation and deallocation that can be easily managed and verified.
So here are some pointers to get you started on learning about the practicalities of resource management:
The basic practice for managing resource across many languages is to define "ownership semantics" for specific resources. You define rules for determining what part of the program is responsible for any particular allocated resource, and rules for how responsibility for a particular resource may be handed off from one part of the program to another.
Typically ownership semantics are defined such that the part of a program that allocates a resource is responsible for it. That may seem obvious, but there are alternatives. E.g. a program could designate a single entity that takes responsibility for cleaning up everything, and then the rest of the program just allocates at will and has nothing to do with clean-up. But more commonly whatever allocates a resource takes responsibility for it.
For example a function that allocates some dynamic memory to perform its task also frees that memory when its done:
void foo(int n) {
int *arr = malloc(n * sizeof(int));
// ...
free(arr)
}
Another way to 'take responsibility' for an allocated resource is to be explicit about about requirements for resource management when resources are passed off. For example a function which needs to allocate memory and pass that memory back to the caller may specify "callers of foo() must call free_foo(foo_results) when the foo results are no longer needed."
foo_t *foo() {
foo_t *f = malloc(sizeof(foo_t));
// ...
return f;
}
void free_foo(foo_t *f) {
free(f);
}
Exceptions
For correct resource management whatever rules of ownership semantics have been designed must be followed in all circumstances. There's one language feature supported by C++ that has historically given some people trouble, making them think they'd correctly handled resource management responsibilities when in fact they hadn't. This feature is exceptions.
I won't go into details about exceptions, but it suffices to say that they are the reason that code such as:
doSomething();
cleanup();
is incorrect. And once you learn the idiomatic C++ way to manage resources it should be absolutely obvious that the above is wrong, without you even needing to know what doSomething() does. (One common criticism of exceptions is that they require you to know if doSomething() might throw an exception in order to know how to do the cleanup, which could require manually examining a huge amount of code. But since one can do the cleanup correctly without knowing if doSomething() throws, that criticism is incorrect.)
C++
In C++ a specific practice for managing resources has been developed, called RAII, for Resource Acquisition Is Initialization. It's reliable and easy to use, and correctly handles circumstances such as exceptions. Under RAII a resource is represented as an object, and the correct ownership semantics are encoded into the object's special functions: its destructor, copy/move constructors, and copy and move assignment operators.
Thus you acquire a resource by initializing an object of the right type and you access the resource through that object. If the resource can be copied or moved then you can copy or move the object. If the resource is fundamentally not copyable or moveable then the object is non-copyable or non-moveable, and trying to copy or move it will produce a compiler error.
Some resource managing, RAII types in the C++ standard library are:
std::array: a template class that manages a static, in-place memory buffer, presented as an array of objects
std::vector: a template class that manages dynamic memory, presented as a resizable array of objects.
std::string: a template class that manages static and/or dynamic memory, presented as a resizable array of char.
std::shared_ptr: a template class that implements reference counting ownership semantics. By default the resource is a dynamically allocated object, but this can be configured.
std::unique_ptr: a template class that implements unique ownership semantics. By default the resource is a dynamically allocated object or array, but this can be configured.
For more info on resource management in C++ you can visit http://exceptionsafecode.com/
You should probably just delete f1, as the main function terminates. The first one is allocated on the heap dynamically and it remains allocated though-out execution, and it needs to be deleted. As for the second one, you declare it statically (on the stack), and when the function getFloatArrayTwo() terminates, it deallocates already the vector, deleting it again my result a runtime double delete error. After showFloatArray(f2); you should put delete f1, and the leaks should dissapear.
Hope this to be of help.

Using a Constructor through pointer

I have a problem.
The compiler keeps warning me for invalid use of the constructor.
All i wanted to do is to create a new course in the class. whats wrong?
int StArray::addCS_Course(int id, int CourseNum, char* CourseName,int HwNum, float HwWeigh, bool Takef, char* BookName){
int i;
CS_Course* course;
if ((CourseNum<0)||(HwNum<0)||(HwWeigh<0)||(HwWeigh>1))
return 0;
for (i=0;i<StudentNum_;i++){
if (Arr_[i]->getID()==id) {
course=(CS_Course*)malloc(sizeof(CS_Course*));
if (course==NULL) {
fprintf(stderr,"Malloc failed\n");
exit(0);
}
course->CS_Course::CS_Course(CourseNum,CourseName,HwNum,HwWeigh,Takef, BookName);
if (Arr_[i]->addCS_Course(course)==1)
return 1;
else
{
free(course);
return 0;
}
}
}
return 0;
}
To create a new object in C++, you don't do this:
course = (CS_Course*) malloc(...);
course->CS_Course::CS_Course(...);
you do this:
course = new CS_Course(...);
That code looks after both allocating memory and calling the constructor.
You then delete your object with delete course; rather than free(course);
(But as juanchopanza points out in the comments, it's considered bad form to create objects on the heap in C style like this - you should prefer to use standard library containers and avoid the use of new. That's a whole nother discussion - you might want to read a tutorial on modern C++.)
Edit by #RemyLebeau: If you need to construct an object in existing memory, use placement new instead:
buffer = malloc(...);
course = new (buffer) CS_Course(...);
But then you have to call the destructor manually:
course->~CS_Course();
free(buffer);
malloc(sizeof(CS_Course*)) allocates enough space for a pointer to a CS_Course, not a CS_Course itself. If malloc were the right way to dynamically allocate memory for an object, you would need to call it like this:
malloc(sizeof(CS_Course));
However, malloc isn't the right way to do this; in C++, you use new to dynamically allocate memory for objects:
course = new CS_Course; //Use the default constructor
or
//Use constructor with 2 parameters
course = new CS_Course(constructor_param1, constructor_param2);
Of course, if you don't need a pointer, you can (and should) create a CS_Course object like this (generally referred to as allocating on the stack):
CS_Course course; //default constructor
//constructor with 2 parameters
CS_Course course2(constructor_param1, constructor_param2);

How to free memory of dynamic struct array

As someone who never dealt with freeing memory and so on, I got the task to create a dynamic array of struct and create functions to add or delete array elements. When deleting I have to free the memory which is no longer necessary.
when deleting the 2nd element of an array of the size of 3, I move the 3rd element to the 2nd position and then delete the last one. When deleting the last one, I always get an error... Is there anyone who can find an solution for me?
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend* friendList = new myFriend[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = *tempFriend;
friendList[1] = *tempFriend2;
friendList[2] = *tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete &(friendList[2]); //and delete 3rd element to free memory
}
Why did you create temporary variables? They're not even needed.
If you use std::vector and std::string, the problem you're facing will disappear automatically:
std::vector<myFriend> friendList(10);
friendList[0]->number=1;
friendList[0]->name = "ABC";
friendList[1]->number=2;
friendList[1]->name = "XYZ";
friendList[2]->number=3;
friendList[2]->name = "123";
To make it work, you should redefine your struct as:
struct myFriend {
int number;
std::string name;
std::vector<std::string> hobbys;
};
If you're asked to work with raw pointers, then you should be doing something like this:
struct Friend
{
int number;
char* name;
};
Friend * friends = new Friend[3];
friends[0]->number=1;
friends[0]->name = new char[4];
strcpy(friends[0]->name, "ABC");
//similarly for other : friends[1] and friends[2]
//this is how you should be deleting the allocated memory.
delete [] friends[0]->name;
delete [] friends[1]->name;
delete [] friends[2]->name;
delete [] friends; //and finally this!
And if you do any of the following, it would be wrong, and would invoke undefined behavior:
delete friends[2]; //wrong
delete &(friends[2]); //wrong
It is impossible to delete a subset from array allocated by new []
myFriend* friendList = new myFriend[10];
You have a single whole array
+------------------------------------------------------------------+
| friendList[0] | friendList[1] | ..... | friendList[9] |
+------------------------------------------------------------------+
You can not delete &(friendList[2]).
You get from C++ whole array of 10 elements.
This array starts from friendList (or &(friendList[0])).
operator delete with pointer to the address returned by new (i.e. friendList) is valid
only.
Two things I noticed. (1) You are apparently supposed to "create functions to add or delete elements" but you haven't done that, you have only created one function. (2) You are making your work harder than it needs to be by using a struct that also needs to manage memory. I suggest you use a simpler struct.
Your assignment is, in effect, to make a simple 'vector' class, so I suggest that you do that. Start with a struct that is empty. If the teacher requires you to use the myFriend struct as written, you can add that in after you finish making your vector like functions. I'm going to assume that you aren't allowed to make a class yet because most instructors make the mistake of leaving that until last.
struct MyStruct {
int value; // start with just one value here. Dealing with pointers is more advanced.
};
MyStruct* array;
int size;
int capacity;
void addMyStruct(MyStruct& value); // adds a MyStruct object to the end.
void removeMyStructAtPosition(int position); // removes the MyStruct object that is at 'position'
// I leave the functions for you to implement, it's your homework after all, but I give some clues below.
void addMyStruct(MyStruct& value) {
// First check that there is enough capacity in your array to hold the new value.
// If not, then make a bigger array, and copy all the contents of the old array to the new one.
// (The first time through, you will also have to create the array.)
// Next assign the new value to array[size]; and increment size
}
void removeMyStructAtPosition(int position) {
// If the position is at end (size - 1,) then simply decrement size.
// Otherwise you have to push all the structs one to the left (array[i] = array[i + 1])
// from position to the end of the array.
}
int main() {
// test your new class here.
// don't forget to delete or delete [] any memory that you newed.
}
The array size is fixed at 10, so you don't need to delete any elements from it. But you do need to delete the name and hobbys elements of friendList[1] (and before you overwrite it). There are two problems here:
You are setting friendList[0]->name = "ABC"; Here, "ABC" is a constant zero-terminated string somewhere in memory. You are not allowed to delete it. So you have to make a copy.
You want to delete hobby[i] whenever it was assigned. But in your code, you can't tell whether it was assigned. So you have to set every element to 0 in the constructor, so that you will later know which elements to delete.
The proper place to delete these elements is in myFriends's destructor.
It seems the point of the question is to manage a dynamic array. The main problem is that he is using an array of friendList. Use an array of pointers to friendList:
struct myFriend {
myFriend() {
number=0;
hobbys = new char*[10];
}
int number;
char* name;
char** hobbys;
};
int main() {
myFriend** friendList = new myFriend*[10];
myFriend* tempFriend = new myFriend;
tempFriend->number=1;
tempFriend->name = "ABC";
myFriend* tempFriend2 = new myFriend;
tempFriend2->number=2;
tempFriend->name = "XYZ";
myFriend* tempFriend3 = new myFriend;
tempFriend3->number=3;
tempFriend3->name = "123";
friendList[0] = tempFriend;
friendList[1] = tempFriend2;
friendList[2] = tempFriend3;
friendList[1] = friendList[2]; //move 3rd element on 2nd position
delete friendList[2]; //and delete 3rd element to free memory
}
But everybody else is right -- there are major issues around memory allocation for both 'hobbys' and for 'name' that you need to sort out separately.
To do your homework I'd suggest to learn much more about pointers, new/delete operators, new[]/delete[] operators (not to be confused with new/delete operators) and objects creation/copying/constructors/destructors. It is basic C++ features and your task is all about this.
To point some directions:
1) When you dynamically allocate the object like this
MyType* p = new MyType;
or
MyType* p = new MyType(constructor_parameters);
you get the pointer p to the created object (new allocates memory for a single object of type MyType and calls the constructor of that object).
After your work with that object is finished you have to call
delete p;
delete calls the destructor of the object and then frees memory. If you don't call delete your memory is leaked. If you call it more than once the behavior is undefined (likely heap corruption that may lead to program crash - sometimes at very strange moment).
2) When you dynamically allocate array like this
MyType* p = new MyType[n];
you get the pointer p to the array of n created object located sequentially in memory (new[] allocates single block of memory for n objects of type MyType and calls default constructors for every object).
You cannot change the number of elements in this dynamic array. You can only delete it.
After your work with that array is finished you have to call
delete[] p; // not "delete p;"
delete[] calls the destructor of every object in the array and then frees memory. If you don't call delete[] your memory is leaked. If you call it more than once the behavior is undefined (likely program crash). If you call delete instead of delete[] the behavior is undefined (likely destructor called only for the first object and then attempt to free memory block - but could be anything).
3) When you assign the struct/class then operator= is called. If you have no operator= explicitly defined for your struct/class then implicit operator= is generated (it performs assignment of every non-static member of your struct/class).