Make instance of class on existing variable - c++

How i can make c++ instance on existing variable
This is my header:
#ifndef PERSON_H_
#define PERSON_H_
class Person{
private:
std::string name = "default";
public:
void setName(std::string name);
}
#endif
This is my person.cpp
#include "person.h";
void setName(std::string name){
this->name=name;
}
And my main cpp file
#include <iostream>
int main(){
Person p;
p.setName("Jack");
//so person now have name Jack.
//here is my problem
p=new Person;
//get error.So how i can on variable p make new instance of Person for return all to default values
return 0;
}

p = Person();. In most cases p = {}; will also work.

new gives you a pointer to a new instance of Person. A HolyBlackCat pointed out, you are not using a pointer here. So either use p = Person() or go with pointers from the very beginning with Person *p = new Person(). However, in this case, I really do not see any need for pointers.

Person* p = new Person(); If you do want to make a new instance use pointer of type Person which will point to the memory address allotted by the new operator. Do whatever operation you want to perform. Since you are using new, make sure to use a delete operator to prevent memory leaks.delete p; delete will basically delete the value at the address pointed by p and assign a nullptr to it so that it doesn't become a dangling pointer. Then again if you want to assign new instance you can use the new operator. Now will p point to a different memory location which is the address of the new object.
-Person *p = new Person();
//perform operations
delete p;
p = new Person();

Related

How do I convert this example to use unique_ptr instead of the generic pointer?

Here's the code. I've added a comment to identify the location where I would like the modification (if possible) to be made. Essentially, to avoid the mistakes while using raw pointers, I felt it would be more ideal to use smart pointers here. Do let me know what you think would the ideal approach be!
class Airline {
public:
virtual double TicketCost(double miles, string class_name) = 0;
protected:
double OperatingCost(double miles, string class_name);
};
double Airline::OperatingCost(double miles, string class_name){
return 50 + 0.25*miles;
}
class Delta : public Airline {
public:
double TicketCost(double miles, string class_name) override{
return 1.0*miles + OperatingCost(miles, class_name);
}
};
class Southwest : public Airline {
public:
double TicketCost(double miles, string class_name) override{
if(class_name=="Economy"){
return 0.5*miles + 50;
}
else{
return 150.0;
}
}
};
// How to modify this to use unique_ptr?
unordered_map<string, Airline* > airline_map{
{"Delta", new Delta},
{"Southwest", new Southwest}
};
vector<vector<string>> input{
{"Delta", "100.0", "Economy"},
{"Southwest", "150.0", "Business"}
};
int main()
{
for(const auto& vec_string: input){
const string& airline_name = vec_string[0];
const double miles = stod(vec_string[1]);
const string& class_name = vec_string[2];
// These lines would also have to be modified
auto* airline_ptr = airline_map[airline_name];
cout<<airline_ptr->TicketCost(miles, class_name)<<endl;
delete airline_ptr;
}
return 0;
}
// How to modify this to use unique_ptr?
unordered_map<string, Airline* > airline_map{
{"Delta", new Delta},
{"Southwest", new Southwest}
};
It is straightforward:
unordered_map<string, unique_ptr<Airline> > airline_map{
{"Delta", make_unique<Delta>()},
{"Southwest", make_unique<Southwest>()}
};
(note: unique_ptr is std::unique_ptr and make_unique is std::make_unique. I assume you wrote using namespace std; somewhere)
// These lines would also have to be modified
auto* airline_ptr = airline_map[airline_name];
cout<<airline_ptr->TicketCost(miles, class_name)<<endl;
delete airline_ptr;
Yes they would. Do you really want to delete the airline here or leave it alone?
Right now, your code deletes the airline, but the pointer is still in airline_map pointing to the empty space where the airline used to be, and if you accidentally used it again, you could have a problem. With unique_ptr you are forced to decide what to do with this pointer.
Option 1: leave the airline alone and don't delete it. You can only have one unique_ptr, and it has to stay in the map if we want it to stay in the map, so we can access the airline like this:
// .get() gets a normal pointer and leaves the unique_ptr alone
auto* airline_ptr = airline_map[airline_name].get();
cout<<airline_ptr->TicketCost(miles, class_name)<<endl;
Option 1b:
// the unique_ptr stays alone and airline_ptr is a reference to the unique_ptr
auto& airline_ptr = airline_map[airline_name];
cout<<airline_ptr->TicketCost(miles, class_name)<<endl;
Option 2: take the pointer out of the map and delete it, leaving the airline name still in the map, but with a null pointer. Doesn't make a lot of sense to me, but I include it here so you can how unique_ptr works:
// Move the unique_ptr out of the map, leaving a null pointer behind in the map
// airline_ptr is a unique_ptr
auto airline_ptr = move(airline_map[airline_name]); // std::move
cout<<airline_ptr->TicketCost(miles, class_name)<<endl;
// when airline_ptr goes out of scope the airline is deleted
Option 3 is to delete the airline from the map. Maps are annoying; there are lots of ways you could erase a thing from a map. I'll let you pick your favourite way.

Deleting all pointers to same object

I have something like this:
void foo(){
Student *a0 = new Student();
Student *a1 = new Student();
Student *a2 = new Student();
Student *a3 = new Student();
}
I have another function
void foo2(){
Student* delStudent;
delStudent = ll.ReturnStudentToDelete(); //this function returns a pointer to delete student
delete delStudent ;
delStudent = NULL;
}
suppose, ll.ReturnStudentToDelete() returns address of a2, above code deletes this object. I want also to set pointer 'a2' to NULL. But I don't know how to retrieve a2 pointer so that to set it to NULL.
Currently I have 2 pointers (a2 and selStudent) which point to same object
Also, I was asked to use operator*() and operator->(). But I didn't get that at all, so I try to do my best. Could you please post simple template example of how that may be implemented. I understand that above raw pointers are bad to use
Based on your code, since you do this:
void foo(){
Student *a0 = new Student();
...
}
Actually, you never store the pointers. In fact this means that when you call foo you will instantly leak all of the memory you create, because you have not stored these pointers. Not only can the ll.ReturnStudentToDelete() function not get the a2 pointer, it won't be able to get any relevant pointer.
You should start with seeing if you can avoid using a pointer. For example, perhaps your code could work like this:
Student someStudent;
...
someStudent.doSomething();
Or if you really do need a group of students:
std::vector<Student> groupOfStudents;

Is a pointer to a stack object deleted when out of scope?

I'm having a hard time trying to understand exactly what I'm supposed to do with my pointer members in my classes. I know that any pointer created with new[] must be deleted with delete[]
But, what if my pointer points to the address of an object created on the stack? Do I have to delete it? Or will it be deleted when the class is destroyed. And if so, in what way am I supposed to delete it? The clarify the issue, here's some of my code.
Moves header file: Moves.h
#pragma once
#include "ShuffleBag.h"
class Character;
class Moves
{
private:
Character* pm_User;
ShuffleBag m_HitChances;
public:
Moves (Character& user);
~Moves ();
};
We can see that I have a pointer member to a character object.
Moves Source File: Moves.cpp
#include "Moves.h"
#include "Character.h"
Moves::Moves (Character& user)
{
m_HitChances = ShuffleBag ();
m_HitChances.Add (true, 8);
m_HitChances.Add (false, 2);
pm_User = &user;
}
Moves::~Moves ()
{
}
And here we can see that I assign this pointer to the address of the passed in reference of the character object.
Character Header File: Character.h
#pragma once
#include "Moves.h"
#include "ShuffleBag.h"
class Character
{
public:
int m_Health;
int m_Energy;
Moves* pm_Moves;
public:
Character ();
Character (int health, int energy);
~Character ();
};
Likewise, here I have a pointer to a move set for this character. This is because the moves do not have a default constructor.
Character Source File: Character.cpp
#include "Character.h"
Character::Character ()
{
m_Health = 100;
m_Energy = 50;
pm_Moves = &Moves (*this);
}
Character::Character (int health, int energy)
{
m_Health = health;
m_Energy = energy;
pm_Moves = &Moves (*this);
}
Character::~Character ()
{
}
And here I assign this pointer the address of the newly created Moves object. So my question in a TL;DR format is this:
Are my pointers pointing to stack objects and when the classes die, will the pointers themselves? Or will I have to delete them?
You only need to call delete on a pointer that is returned by new. There is no exception to this rule.
In your case though,
pm_Moves = &Moves(*this);
is assigning a pointer to an anonymous temporary Moves(*this);. It's that pointer that's immediately invalided after the statement! The program behaviour on using that pointer for anything is undefined.
So you obviously need to redesign all this. Consider looking at std::unique_ptr when you refactor.
I know that any pointer created with new[] must be deleted with
delete[]
I've seen this confusion over and over again. You don't delete pointers, you delete objects. Or better to understand, if you talk about malloc / free: you don't free pointers, you free memory. The pointer just points to the object(s) / memory you need to delete.
E.g.:
int a = 24; // just an int
int* p1 = new int; // new allocates memory for an int,
// creates an int at that location
// and then returns a pointer to this newly created int
// p1 now points to the newly created int
int* p2 = p1; // p2 now also points to the created int
p1 = a; // p1 now points to a
// what do we delete now? p1?
// no, we don't delete pointers,
// we delete objects dynamically created by new
// what pointer points to those objects?
// at this line it is p2
// so correct is:
delete p2;
There is no new dynamic element created in this class, so you cannot destroy it.

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;

Free the memory of a pointer to a struct

I am new to C++ and implemented the following struct:
struct Person {
String name;
int age;
};
Now I create a new object:
Person *p = new Person();
p->name = "name";
p->age = 211;
and push it onto a stack:
stack.push(*p);
I have a while(!stack.empty()) expression and in there I process every element I pushed onto the stack.
Now where do I free the memory? In the while-loop I do the following:
Person *current = &stack.front();
stack.pop();
// do stuff
delete current;
Sadly, the delete current statement throws some kind of exception.
What do I do wrong? Thanks for your help.
You would need to delete p after pushing into the stack. The stack stores its own copy of the object pushed into it, so there is no need to do anything to it after popping.
But the real solution is to not use new in the first place:
Person p = {"name", 211};
...
stack.push(p);
or just
stack.push(Person{"name", 211});
Then
Person current = stack.front();
stack.pop();
So, no need to deal directly with memory management.
When you push something on to a stack, you don't push the original object - you push a copy of the object. To free the memory of the original object, you need to do it right at the point after you've pushed it.
Or you can skip that altogether and don't use new to create the object in the first place:
Person p;
p.name = "name";
p.age = 211;
stack.push(p);
You don't need to make a pointer. If you have to, then use a smart pointer to free the memory for you: std::unique_ptr<Person> p(new Person);