deleting an element in a struct by using delete operator - c++

I have a struct like this:
struct m_doc{
char id[30];
int ISBN[30];
char title[50];
char author[50];
int year[30];
};
As I'm trying to delete an element inside it by using the delete operator, this happened:
if (doc.id[i] == doc.id[j])
delete[] doc.author[j], doc.id[j], doc.ISBN[j], doc.title[j], doc.year[j];//expression must have pointer type
The error is on the doc of doc.author only, while the others are fine.

Array declared that way are deleted automatically when they go out of scope.
You only have to delete arrays declared like this:
int* array = new int[30];
//Do work
delete[] array;
You should however prefer std::vector over the latter array style and std::array instead of the arrays you used in your code. It is much less error prone.
In your case (and almost always), std::vector is the most appropriate data type. Then you can do stuff like this:
if (doc.id[i] == doc.id[j]) {
doc.author.erase(doc.author.begin() + j);
//and so on
}

You may only delete what you have created with new. You could create a pointer as follows:
m_doc *instance = new m_doc();
Then you could delete that later...
delete m_doc;
Or you could create each of the members as pointers which are manually newed up.

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++

Create new struct, insert into list, re-use pointer, return in vector... whether and how to delete?

In C++ code that I wrote to demonstrate an algorithm in an answer, I'm creating structs in a function using new, storing them in a list, moving them to a vector, then returning the vector:
struct my_struct {int a, b, c;};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
my_struct *new_struct = nullptr;
while (...) {
...
if (!new_struct) {
new_struct = new my_struct;
new_struct->a = ...
}
...
if (new_struct) {
new_struct->b = ...
my_list.insert(current, *my_struct);
my_struct = nullptr;
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
It compiles and seems to work correctly, however I'm more used to JavaScript and this code just feels like translated JavaScript; I'm specifically wondering whether I'm creating memory leaks, and whether I have to delete the structs in the calling function (and how).
Yes, you have a memory leak. If you invoke the new command, you will need to invoke a delete command in the future to free the memory allocated by new.
So, in this statement:
my_list.insert(current, *my_struct);
you are indeed copy the contents of *my_struct, not getting the ownership of it. So, in the following statement:
my_struct = nullptr;
You just got a memory leak.
To solve this, change your design to use smartpointer, for example, unique_ptr, or, better yet, dont use pointer at all, and just use a plain object:
my_struct new_struct;
As others in the question section have already pointed out, you probably shouldn't use new at all. The only reason to use pointers there at all is the if(newstruct) checks, if they are an essential part of your algorithm.
But if you use new, you should delete, too. It's safe to do that after inserting the struct into the list or vector - the list and vector contain copies.
Beginning with C++17, std::optional (and before that, boost::optional) is a sensible alternative solution for your specific problem here. It removes the need for pointers and the danger of memory leaks but at the same time still gives you a "nothing" state.
Your pseudo code would become something like:
// this is the correct way of defining a struct in C++:
struct my_struct {
int a;
int b;
int c;
};
std::vector<my_struct> myFunction(...) {
std::list<my_struct> my_list;
std::list<my_struct>::iterator current = my_list.begin();
std::vector<my_struct> my_vector;
std::optional<my_struct> new_struct; // new_struct does not hold a value
while (...) {
...
if (!new_struct.has_value()) { // if it does not hold a value...
new_struct = my_struct(); // it holds a value now (a default my_struct)
new_struct->a = ... // access syntax like a pointer
}
...
if (new_struct.has_value()) {
new_struct->b = ...
my_list.insert(current, *new_struct); // dereference syntax like a pointer
new_struct.reset(); // it no longer holds a value now
}
...
if (...) {
current->c = ...
my_vector.push_back(*current);
current = my_list.erase(current);
}
...
}
return my_vector;
}
Note how the syntax of std::optional deliberately mimics that of pointers.

C++ Is delete[] enough to clean up after an array?

In the code below I'm allocating an array dynamically by using the new keyword. Before I run out of scope I call delete[] on my array, and afterwards I set the punter to null.
My Question is, if this is enough, will delete[] make sure that the allocated memory for all 3 Car objects in my array is released. Or do I have to do something specific to release the memory used by every single object?
void main()
{
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
Also, the car class looks like this. Is it also enough to set the name to null here. Name is a char pointer. Or maybe it isn't needed to set the pointer to null since it isn't referencing anything on the heap.
Car::Car(char * newName)
{
name = newName;
}
Car::~Car()
{
name = nullptr;
}
EDIT:
First of all, thanks for all the great answers and comments. I learned a lot from reading them.
Now I understand, that I need to specify a size when declaring a dynamic allocated array.
Besides that I also understand, that I need to stop using new as much as I do. I guess its better to throw the objects on the stack, and let them go out of scope at some point. Besides that I guess my destructor on my car does nothing.
After reading the comments and the answers, I'v change my code to this:
int main()
{
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
delete[] myArray;
myArray = nullptr;
}
In your case, you have already leaked the memory from your calls to new Car("BMW") and have lost the pointer to be able to free the memory.
This line:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
Creates an array of 3 Car objects, then for each entry it creates a new Car object, uses it to initialize the object in the array, then forgets about the new object.
It can be more simply written like this:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
or even
Car * myArray = new Car[3]{ "BMW", "AUDI", "SKODA" };
In which case your delete[] is enough to free up the memory used.
Note that
Car::~Car()
{
name = nullptr;
}
does not do anything to free memory. Once the Car destructor is called, no one should be accessing name for that object again (in fact it is undefined behavior), so there is little point in setting it to null.
Edit Note: As pointed out by R Sahu and Aslak Berby, Car * myArray = new Car[]{ ... }; is not a valid way to make an array, use Car * myArray = new Car[3]{ ... }; instead.
You cannot use:
Car * myArray = new Car[]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
You need to specify a size.
Car * myArray = new Car[3]{ * new Car("BMW"),*new Car("AUDI"), * new Car("SKODA") };
Even after that, calling
delete [] myArrary;
is going to leak memory. That line is equivalent to:
Car * myArray = new Car[3];
Car* car1 = new Car("BMW");
Car* car2 = new Car("AUDI");
Car* car3 = new Car("SKODA");
myArray[0] = *car1;
myArray[1] = *car2;
myArray[2] = *car3;
The line
delete [] myArrary;
does not delete the objects allocated separately for car1, car2, and car3. You'll have to explicitly delete those too.
delete car3;
delete car2;
delete car1;
However, you cannot use
Car * myArray = new Car[3];
since Car does no have a default constructor. You can add a default constructor to Car. Failing that you can to use:
Car * myArray = new Car[3]{ Car("BMW"), Car("AUDI"), Car("SKODA") };
Then, it is sufficient to use:
delete [] myArrary;
to deallocate the memory.
Car * myArray = new Car[X];
This code already creates X Car objects. All you have to do is use them really..
However, I think your confussion lies here: this is another approach to do it
Car ** myArray = new Car*[3] { new Car("BMW"), new Car("AUDI"), new Car("SKODA") };
for (int i = 0; i < 3; i++)
delete myArray[i];
delete[] myArray;
This code allocates an array of 3 Car* pointers. Therefore, you have not created any Car object yet, which is why you initialize each Car* pointer with with a new Car() call, which actually creates the Car object.
yes it is sufficient only if you are creating a plain array of Car elements since an array name is a pointer to its first element
You are informing the compiler that its an array by specifying the []
In your case you seem to be creating car pointers so you have to clean up the memory location occupied by each car and then the memory allocated for the whole array.
What you incorrectly attempted to do is this but don't do it. Its convoluted
Car** cararrptr = new Car*[3];
cararrptr[0] = new Car("win");
cararrptr[1] = new Car("lin");
cararrptr[2] = new Car("ios");
//now to clean up
delete cararrptr[0];
delete cararrptr[1];
delete cararrptr[2];
delete[] cararrptr;
Take a look at this discussion
delete[] an array of objects
Basically you need a delete (or delete[]) for every new. But in a more complex program this can be very difficult (and error prone) to assure.
Instead of raw pointers you should learn to use smart pointers like shared_ptr or unique_ptr. These let you avoid explicit new and delete in most cases.
I agree with the comments that you are using the keyword new too much.
I suggest using std::vector instead.
Here is a working example where the class Garage has a vector of Car's on the heap/freestore and later deleting it with destructor ~Garage
Example for illustration only:
class Car {
Car();
string m_name;
public:
Car(const string &);
void print();
};
Car::Car(const string &s) : m_name{s} { }
void Car::print()
{
cout << m_name << endl;
}
class Garage {
string m_name;
vector<Car> *m_cars; // for allocating on heap
public:
Garage(const string &);
~Garage();
void add(const Car &);
void print();
};
// Creating a new vector on heap
Garage::Garage(const string &s) : m_name{s}, m_cars{new vector<Car>} { }
Garage::~Garage()
{
delete m_cars; // deleting the vector.
}
void Garage::add(const Car &c)
{
m_cars->push_back(c);
}
void Garage::print()
{
for (auto car : *m_cars)
car.print();
}
int main()
{
Garage garage{"Luxury garage"};
garage.add(Car("BMW"));
garage.add(Car("Audi"));
garage.add(Car("Skoda"));
garage.print();
}
Using new vector above is only for demonstration, it's not needed. Using a std::vector without new is faster and safer for this purpose and you won't need to delete it after use.
Also consider using Smart Pointers instead of using new.
You can add a object to the heap or the stack. If you add it to the heap you create it dynamicaly as you go. This is done using new and you get a pointer in return.
Car *aCar=new Car("BMW");
If you create it on the stack, you will just define it as you do with other variables.
Car anotherCar("BMW");
If you create it on the heap, you also need to deallocate it from the heap. This is done with delete.
delete aCar;
You never dealocate a object you created on the stack. That will automtically be dealocated when you go out of scope.
As for creating a array, you can create a array of statick or dynamicall objects.
Dynamical:
Car **cars=new Car*[3];
cars[0]=new Car("BMW");
cars[1]=new Car ....
All of those need to be deleted seperatly. No cascading here.
delete cars[0];
delete cars[1];
// And finaly the array.
delete[] cars;
You can create them staicaly:
Car cars[]={"BWM", "AUDI"};
This time all the objects including the array is pushed to the stack and will be deleted when you go out of scope.
In between you can create stuff that is a stackbased array that points to heap allocated objects, or a heapallocated static array as other suggest here.
As for C++ I would suggest using the std:: library and in this case std::vector;
Either:
std::vector<Car *> myArray;
myArray.push_back(new Car("BMW"));
.....
// Cleanup:
for(auto car : myArray)
delete car;
Or:
Car car;
std::vector<Car> myArray;
car.SetType("BMW");
myArray.push_back(std::move(car));
I am not sure how I ended up here on a two year old post. None of the answers really give a simple C++ solution so here is a 60 second solution using containers and no new/delete in sight.
#include <iostream>
#include <string>
#include <vector>
struct Car {
// Allows implicit conversion from char *
Car(const char *manufacturer) : manufacturer_(manufacturer) {}
std::string manufacturer_;
};
int main() {
std::vector<Car> cars{ "BMW", "AUDI", "SKODA" };
for (const auto& car : cars) {
std::cout << car.manufacturer_ << "\n";
}
}
live demo
No. delete []myArray Will merely result in something called a dangling pointer.
Which basically means that the program no longer owns the memory pointed to
myArray, but myArray still points to that memory.
To avoid dangling pointers assign your pointer to nullptr after deletion.
delete[]myArray;
myArray = nullptr;

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).