#include<iostream>
#include <string>
using namespace std;
class Human
{
private:
int *age;
string *name;
public:
Human(string p_name, int value)
{
*name = p_name;
*age = value;
cout <<"Name of Person is "<<*name <<" and age is "<<*age<<endl;
}
~Human()
{
delete name;
delete age;
cout<<"Destructor release all memory So now name is "<<*name << " and age is "<<*age<<endl;
}
void display()
{
cout << "The name is "<<*name <<" and age is "<<*age<<endl;
}
};
int main()
{
int age = 24;
string name = "CODY";
Human cody(name,age);
cody.display();
}
It is not printing anything.... What is happening can somebody explain it please.... Is it due to I implemented pointer variable incorrectly...Why is it incorrect please tell me then and what will be the alternative solution
why pointer variable inside private class can't point to outside variable of class
The premise of your question is faulty. A private member variable can point to outside of the class.
Human(string p_name, int value)
{
*name = p_name;
*age = value;
You didn't initialise the pointers, so indirecting through them results in undefined behaviour. Don't do this.
cout << "The name is "<<*name <<" and age is "<<*age<<endl;
Here, you indirect through the invalid pointers and the behaviour of the program is undefined.
delete name;
delete age;
cout<<"Destructor release all memory So now name is "<<*name << " and age is "<<*age<<endl;
Even if the pointers weren't invalid, it would be wrong to delete them. You didn't create any objects with allocating new, so there is nothing to delete. Deleting the pointers that weren't returned by allocating new will result in undefined behaviour. Don't do this.
Furthermore, even if delete had been valid, that would invalidate the pointers, and the successive indirection through the newly invalidated pointers in the cout statement would result in undefined behaviour. Don't do this either.
Solution: Remove the delete lines.
A solution where the class points to variables outside of the class: In order to refer to an object outside of a function, you need to use indirection. You can use a pointer parameters for example, and initialise the members to point to the same objects:
Human(string* p_name, int* value)
: name(p_name), age(value)
{}
// example usage:
Human cody(&name, &age);
Note that storing pointers in members is precarious because you must be aware of the relative lifetimes of the pointed objects, and the object containing the pointers. You must be sure that the pointers don't outlive the pointed objects.
Considering the problems of the referential design of your class, I urge you to consider using values instead. This would likely be more useful class in general:
struct Human {
std::string name;
int age;
void display()
{
std::cout
<< "The name is "
<< name
<< " and age is "
<< age
<< '\n';
}
};
int main()
{
Human cody {
.name="CODY",
.age=24,
};
cody.display();
}
There are several mistakes in your given program as explained below.
Mistake 1
First you need to make sure that the data members age and name point to some variables of appropriate type. Then only you can dereference them. Since you're dereferencing the pointers that don't point to objects of appropritate types, you have undefined behavior in your program.
Human(string p_name, int value)
{
*name = p_name; //Undefined behavior because name doesn't point to an std::string object
*age = value; //Undefined behavior because age doesn't point to an int object
cout <<"Name of Person is "<<*name <<" and age is "<<*age<<endl;
}
Mistake 2
Second you can use delete when you have allocated memory using new. And since you have not allocated any memory using new, it is incorrect to use delete.
~Human()
{
delete name; //not valid
delete age; //not valid
cout<<"Destructor release all memory So now name is "<<*name << " and age is "<<*age<<endl; //undefined behavior as explained in mistake 3
}
Mistake 3
Third you're dereferencing the pointers age and name just after you used delete on them. This again leads to undefined behavior.
cout<<"Destructor release all memory So now name is "<<*name << " and age is "<<*age<<endl; //undefined behavior because you just used `delete` on the pointers and also because they don't point to objects of the appropriate type
Better would be to use smart pointers that will take care of memory management for you. That is, when we use smart pointers we don't have to manually use new and delete.
Just so that you can see how to correct the current 2 mistakes you can refer to the below given modified example:
//this uses constructor initializer list
Human(string p_name, int value): age(new int(value)), name(new std::string(p_name))
{
cout <<"Name of Person is "<<*name <<" and age is "<<*age<<endl;
}
//destructor
~Human()
{
if (name != nullptr && age!=nullptr)
{ //check that
delete name;
delete age;
cout<<"delete used successfully"<<endl;
}
else
{
cout<<"delete not used"<<endl;
}
}
I'm writing a program to manage products, employees and bills of a restaurant in C++.
But I have a problem when writing a function to read information of products from file to the Product struct.
That is C2280 Error and it say something like my code is attemping to reference a deleted function.
I've read for this Error in Google but I don't understand so much.
This is an excerpt of my code:
struct Product
{
string productID;
string productName;
string productType;
int productPrize; //USD
};
/* function to get Products information from file */
bool readProductInformation(ifstream f, ProductList& productList)
{
if (!f.is_open()) {
cout << "Can not onpen file for reading!" << endl;
return false;
}
f >> productList.numberOfProducts;
int amount = productList.numberOfProducts;
if (amount == 0) {
f.close();
return true;
}
PNode* temp = productList.head;
for (int i = 0; i < amount; i++)
{
string str;
getline(f, str, '\n');
stringstream iss(str);
getline(iss, temp->data.productID, '-');
getline(iss, temp->data.productName, '-');
getline(iss, temp->data.productType, '-');
f >> temp->data.productPrize;
temp->next = new PNode;
temp = temp->next;
}
temp = NULL;
f.close();
return true;
}
When I create ifstream f and productList list and call the function again, it comes to the Error!
The ifstream type has no copy constructor because it was intentionally deleted, meaning that you cannot pass it by value as you are doing in the readProductInformation function. More information about ifstream's constructors can be found here, most importantly the following
(3) copy constructor (deleted)
Deleted (no copy constructor).
In order to fix this, just pass the ifstream object by reference instead of by value. This means that the object accessed in the function is actually the same object that is passed in. Changes made to this object are not restricted to inside the function. Here is a good post that goes into more detail about the difference.
So you simply have to change it to
bool readProductInformation(ifstream& f, ProductList& productList)
Why would someone intentionally delete a copy constructor? Because sometimes it doesn't make sense for specific objects to be copied, and if you don't specifically delete an object's copy constructor, the compiler is smart enough to sometimes make one for you allowing you to do what was unintended (copy). Here is a somewhat dense but good source explaining deleting and defaulting functions.
I try to make simple program that will display students names from array of objects called "Student", I know that it can be easily done using vectors but I would like to do that using dynamic array. My code:
class Student {
public:
string name;
Student(string name){
this->name = name;
}
};
void DisplayStudentsNames(Student array[],int length) {
for(int i=0;i<length;i++){
cout << array[i].name << endl;
}
}
int main(int argc, char** argv) {
Student ** array = new Student *[3];
array[0] = new Student("Michael");
array[1] = new Student("Tom");
array[2] = new Student("Timmy");
DisplayStudentsNames(*array,3);
return 0;
}
I am not sure why it does not work, it does compile but program just "stops responding" after displaying first student name. I wonder what is the issue, I have read here that if Class does not have any zero argument constructor you cannot create an array of dynamic objects dynamically, I wonder why is that? I'm just assigining new objects to pointers (in C# that's the normal way creating a class).
Your issue is here
DisplayStudentsNames(*array,3);
What you are actually passing to DisplayStudentNames() here is the first element is the array array. The issue is that array[0] is not an array, it is a pointer to a single object. Therefore when you try and iterate it you get undefined behaviour, an exception would be the best case scienorio here (as you saw with your infinite loop).
You can fix this by changing
DisplayStudentsNames(*array,3);
to
DisplayStudentsNames(array,3);
and DisplayStudentsNames to take Student**
Also this wont work:
cout << array[i].name << endl;
Each element in array is a pointer to a Student object and in C++ accessing an object through a pointer requires using the -> operator (so array[i]->name instead).
Side note:
Student(string name){
this->name = name;
}
This is bad C++, use initaliser lists for setting members on creation instead, as it allows compiler optimisations and is easier to read
I've got a problem with destructor in my class.
The main idea is to use operator overloadings in undefined length vectors ex. u can create object which simulates a euclidian vector like RealVector(3) and then use function fillvec() to fill the table with positions x,y,z.
The problem is when I try to use a destructor to delete alocated memory for table.
Here is my code:
class RealVector{
private:
int dim;
double* tab;
public:
RealVector(int dim){
tab=new double[dim];
}
RealVector(const RealVector & other){
dim=other.dim;
tab=new double[other.dim];
for(int i=0; i<dim; i++){
tab[i]=other.tab[i];
}
}
void fillvec(){
for(int i=0; i<dim; i++){
cin >> tab[i];
}
}
void wri(){
cout << "Vector [";
for(int i=0; i<dim; i++){
cout << tab[i];
if(i!=dim-1)
cout<<", ";
}
cout << "]";
}
RealVector operator+(RealVector & o){
for(int i=0; i<dim; i++)
tab[i]+=o.tab[i];
return *this;
}
~RealVector(){
delete [] tab;
}
}
int main(){
RealVector* w1=new RealVector(3);
RealVector* w2=new RealVector(3);
RealVector* answerr=new RealVector(3);
w1->fillvec();
w2->fillvec();
*answerr=*w1+*w2;
answerr->wri();
}
Can someone explain where I have made mistake?
I can see here few critical bugs.
The first one is the main (in your case) I think. The constructor RealVector(int dim) doesn't initialize the dim member. This dim is later used in many member functions while it's value is not initialized. You can fix it by:
RealVector(const int _dim) : dim{_dim}
{
tab=new double[dim];
}
The second bug is that the dim in the operator+ belongs to the current object and might be bigger than dim of the o object. You should use std::min(dim, o.dim) instead.
The third one (thanks to Mooing Duck for pointing out) is that you are missing the operator= implementation. The default assignment operator performs just a 'flat' copy. Since you are using dynamic memory allocation it is critical to implement the 'deep' copy in the operator=. You can find the examples here.
EDIT
Since the c++11 has been tagged here, I would strongly recommend using smart pointers as well as move constructor and move assignment.
I am cleaning up a toy program I wrote for a class using XCode 5. Part of the assignment was to gain familiarity with dynamic memory allocation (meaning it must use new and delete despite the fact that it would really work fine without it). I am receiving:
HeapOfStudents(67683,0x7fff769a6310) malloc: *** error for object 0x100300060: pointer being freed was not allocated *** set a breakpoint in malloc_error_break to debug
The error happens:
Student::~Student() {
delete firstName; // <- on this line
delete lastName;
delete address;
delete birthDate;
delete gradDate;
delete gpa;
delete crHours;
}
which is being called...
int main() {
string line = "";
vector<Student> students;
//
//Create new students from file
//
ifstream data_file ("heapData");
if (data_file.is_open()) {
while(getline(data_file, line))
students.push_back(*new Student(line)); <- inside this call here
data_file.close();
}
else return 0;
The full Student class is below.
Importantly, I noticed that while each line gets correctly pushed to the vector, when the next Student gets pushed, the previous Student inside the vector gets corrupted. I see the malloc error always on the third iteration of the loop (the file has 50 lines).
The program runs without exception if I change vector<Student> to vector<Student *> and student.push_back(*new Student(line)) to student.push_back(new Student(line)).
My question then is: Can someone please explain what, on a lower level, is happening inside this loop that creates this error?
My guess is that *new Student(line) uses the same pointer each time, so through each iteration, data gets corrupted because it is being freed (although this explanation raises questions), while new Student returns a new pointer each time, preserving the data that was passed to students. I'm thinking that maybe I need to write a copy constructor... This is just my guess.
Here is the Student class. Address and Date are also custom classes that are fairly similar. I didn't include them because they don't seem to be part of the issue.
//Constructors
Student::Student() {
firstName = new string("Testy");
lastName = new string("Testerson");
address = new Address("000 Street St", "", "Citytown", "State", "00000");
birthDate = new Date("01/02/9876");
gradDate = new Date("01/02/6789");
gpa = new string("10.0");
crHours = new string("300");
}
Student::Student(string FN, string LN, string L1, string L2, string C, string S, string Z, string BD, string GD, string GPA, string Hr) {
firstName = new string(FN);
lastName = new string(LN);
address = new Address(L1, L2, C, S, Z);
birthDate = new Date(BD);
gradDate = new Date(GD);
gpa = new string(GPA);
crHours = new string(Hr);
}
Student::Student(string line) {
set(line);
}
//Destructors
Student::~Student() {
delete firstName;
delete lastName;
delete address;
delete birthDate;
delete gradDate;
delete gpa;
delete crHours;
}
//Member Functions
void Student::set(string line) {
firstName = new string(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
lastName = new string(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
address = new Address();
address->setLine1(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
address->setLine2(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
address->setCity(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
address->setState(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
address->setZip(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
birthDate = new Date(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
gradDate = new Date(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
gpa = new string(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
crHours = new string(line.substr(0, line.find_first_of(",")));
line = line.substr(line.find_first_of(",") + 1, string::npos);
}
void Student::printReport() {
cout << *lastName << ", " << *firstName << ", " << address->getAddress()
<< ", " << birthDate->getDate() << ", " << gradDate->getDate()
<< ", " << *gpa << ", " << *crHours << endl;
}
void Student::printName() {
cout << *lastName << ", " << *firstName << endl;
}
string Student::getName() {
return string(*lastName + ", " + *firstName);
EDIT Here's the copy constructors and assignment operators I wrote for the student class should anyone be interested in seeing/critiquing them:
Student::Student(const Student & student){
firstName = new string(*student.firstName);
lastName = new string(*student.lastName);
address = new Address(*student.address);
birthDate = new Date(*student.birthDate);
gradDate = new Date(*student.gradDate);
gpa = new string(*student.gpa);
crHours = new string(*student.crHours);
}
Student& Student::operator=(const Student & student) {
return *new Student(student);
}
It looks like you're not following the Rule of Three, so Bad Things will happen if you copy a Student object. Specifically, both will contain pointers to the same objects, which both will try to delete - so one will try to delete something that the other has already deleted.
The easiest way to give the class valid copy semantics is to disallow copying, by deleting the copy constructor and copy-assignment operator:
class Student {
Student(Student const &) = delete;
void operator=(Student const &) = delete;
// rest of class...
};
Otherwise, if you want the class to be copyable, implement these to do something sensible.
Also, this causes a memory leak:
students.push_back(*new Student(line));
by dynamically creating a Student, copying it into the vector, and discarding the only pointer to the dynamic object. If you're storing objects, then push a copy of a temporary:
students.push_back(Student(line));
Alternatively, you could change the container type to vector<Student*>, and remember to delete each object when you remove its pointer. (That's a reasonable thing to do as an exercise in pointer-wrangling, as you say this is, but don't do it in any program you want to maintain.)
Once you've learnt the grisly details of manual memory management, make life easier for yourself by avoiding dynamic allocation unless absolutely necessary and, when you really do need it, always managing it with smart pointers, containers, and other RAII types, not by juggling raw pointers.
The issue is likely happening because the default copy and assignment operators do not do the right thing -- they copy the pointers. So if you create a temporary Student somewhere you are going to delete the pointers when that temporary is destructed, while the original still points to the same (now deleted) objects. When it is destructed, it is going to try to delete pointers that were already deleted, hence the error.
You need to follow the rule of three: if you need a custom destructor, assignment operator, or copy constructor, you need all of them.
Add the following public members to your class:
Student(Student const &);
Student & operator=(Student const &);
And define them like so:
Student::Student(Student const & other)
{
firstName = new string(other.firstName);
// And so on, for each pointer member.
}
Student & Student::operator=(Student const & other)
{
*firstName = other.firstName;
// And so on, for each pointer member.
return *this;
}
Note that all of this can be avoided by using string firstName; instead of string * firstName; -- in that case, the default destructor, copy constructor, and assignment operator would do the right thing and you wouldn't need to define any of them.
Further, be aware that your Address and Date classes could have the same problem! You have to do these kinds of gymnastics any time you use raw pointers as class members.
One problem you have is that you are keeping a vector of Student objects, instead of a vector of pointers to dynamically allocated objects (of type Student* therefore).
Simply replace your students variable to std::vector<Student*> students;. From then, you can simply push_back the pointer created by new.
The thing is that vector already deals with memory allocation, so the line making the push (that you highlighted in the code) was making a copy of the Student to a position in the vector. The pointer to the dinamically allocated object would become unreachable after that.
As Barmar pointed out, having a vector of pointer also has the advantage of being able to push pointers of subclasses of Student. A simple example on that:
class PhDStudent : public Student { ... }
students.push_back(new PhDStudent(...));
Furthermore, there are many other tweaks you should consider in your class:
Your constructor is taking string parameters by-value, which means they are deeply copied from their origin. Using const string& is preferable here, to avoid unnecessary copies.
As already pointed out by some other answers (by Mike Seymour, cdhowie, Anton Savin and whoever is going to point this out), you should follow the Rule of Three. If you want your class to be copiable, you should also implement the copy constructor and the copy assignment operator. If you're using C++11, you can take advantage of a move constructor and a move assignment as well, so as to reduce the number of allocations when moving those objects.
It may happen that you don't want Students to be copied, but you still want to put them into a vector. In C++11 it can be solved by just adding a move constructor:
class Student {
public:
Student() { ...}
~Student() {...}
Student(const Student&) = delete; // optional: will be deleted implicitly
Student(Student&& other) {
firstName = other.firstName;
other.firstName = nullptr;
// ...
}
};
This way copy constructor and assignment operator will be implicitly deleted, so you'll not be able to make copies. But vector and other containers will use move constructor just fine. This of course puts certain limitations on Student usage.
vector<Student> students;
students.push_back(Student()); // OK, student moves
Student s;
students.push_back(s); // Error: copy constructor for Student is deleted