Why do we use a pointer of object when we want to create a new object like this?
employee *Steve = new employee();
In this case, I want to create an object named Steve.
#include <iostream>
#include <string.h>
using namespace std;
class employee{
private:
char name[40];
int salary;
public:
employee(){
strcpy(name, "unnamed");
salary = 0;
}
char *getName(){
return name;
}
};
int main(){
employee *Steve = new employee();
cout<<"Name: "<< Steve->getName();
}
We do not use pointers when we do not need pointers. When we want to create an object we call a constructor to create an object, but we do not use new nor raw pointers.
employee Steve;
std::cout << "Name: " << Steve.getName() << "\n";
If we dynamically allocate the object then we still do not use new or raw poitners, but container or smart pointers.
In bad tutorials and questionable teaching they use pointers a lot. Often that is because they do not actually aim to teach C++, but rather to teach pointers. In modern C++ the use of raw pointers is limited to rare cases.
There would be more to say about the code you wrote, but I'll leave it at that and refer you to The Definitive C++ Book Guide and List.
Related
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 know this is very basic but somehow working on different technologies I have mashed up my C++ concepts
I have created a simple program but it is giving exception when the destructor is called.
Below is the code:
#include "stdafx.h"
#include<iostream>
using namespace std;
class Employee
{
public:
Employee(char *name){
cout<<"Employee::ctor\n";
myName_p = new char(sizeof(strlen(name)));
myName_p = name;
}
void disp(){cout<<myName_p;}
~Employee()
{
cout<<"Employee:dtor\n\n";
delete myName_p;
}
private:
char *myName_p;
};
int main()
{
Employee emp("check");
emp.disp();
return(0);
}
Requesting all to clear this basic concept. As per my understanding we can't use delete[] because we are not using new[] in this case. Though I have tried using delete[] , but still it was giving error
You REALLY should use std::string here.
It is so much easier, especially for a beginner. The list of errors is:
you are calculating the wrong size of the name, it should be strlen(name)+1, not using sizeof anything.
You also should use new char[strlen(name)+1].
You are copying the data from the string supplied as the argument to the constructor, use strcpy rather than name_p = name - the latter leaks the memory you just allocated, and then you have a pointer to a const char * which you should not delete.
If you fix the allocation so that it is correct, you should then use delete [] name_p;.
However, it you instead use std::string, all of the above problems go away completely, you can just do:
Employee(char *name) name_p(name) { ... }
and get rid of all the problematic new, delete and copying. Of course, name_p is probably no longer a suitable name for the variable, but you get the idea.
Change
myName_p = new char(sizeof(strlen(name)));
myName_p = name;
to
myName_p = strdup(name);
and #include <cstring>. This creates new space and copies the parameter string. In this way, you'll have to call free instead of delete in your destructor.
Otherwise, after the second assignment, you have assigned the string literal "check" to myName_p, and the newly created space is discarded. Then your destructor tries to delete "check" rather than the allocated space, which results in crash.
Also, it is better practice to use std::string rather than old char* strings:
class Employee
{
public:
Employee(char *name): myName_p(name) {
cout<<"Employee::ctor\n";
}
void disp(){ cout << myName_p; }
private:
std::string myName_p;
};
The string class will manage memory for you.
I have two classes, PersonnelLists and Employee. I create an instance of PersonnelLists in my main, like so:
int main() {
PersonnelLists example; //Make a personnel list
...
}
PersonnelLists uses a constructor with member initialisation of a list of employees, the number of employees, and the size of the array:
PersonnelLists::PersonnelLists(): List(new Employee[SIZE]), numEmployees(0), arraySize(SIZE){
}
This results in some null empty employees being created (I think?):
Employee::Employee(): employeeNumber(0), name(NULL), department(NULL) {
}
It is at this line that I get an invalid null pointer error.
I am new with C++, fresh off the boat from Java programming. I'm still a novice with pointers, so I'm not quite sure what I'm doing wrong here.
UPDATE:
As requested, here is the class definition of Employee:
#include <iostream>
class Employee {
public:
Employee(); //constructor
Employee(std::string name, std::string deparment);
void Print() const; //Print this employee's details
void setEmployeeNo(int employeeNum);
private:
int employeeNumber;
std::string name;
std::string department;
};
In Java, new Employee[SIZE] creates an array of null references.
In C++, new Employee[SIZE] creates an array of default-constructed instances of Employee. Your default constructor tries to set name and department to NULL. Attempting to initialize a std::string to NULL would give the error you describe.
There's no "null" string in C++, but you could default-construct name and department, which would set them to empty strings:
Employee::Employee(): employeeNumber(0), name(), department() {
Finally, if List can contain a variable number of elements, I would recommend that you use std::vector<Employee> (which is similar to ArrayList<Employee> in Java).
If name and department are std::strings (or a similar string type), then initializing them with NULL (a null character pointer) is invalid.
If I guessed right, you should default-initialize them instead, as:
Employee::Employee(): employeeNumber(0), name(), department() {
}
But we really can't tell without seeing the class definition of Employee.
As others have pointed out, you should use a std::vector instead of an array. That allows you to only
have valid Employee objects in your "list".
I don't know what the actual definitions of your classes are, so it's kind of hard to identify your problem.
But an option in modern C++ of doing that is to use a std::vector<Employee> data member inside PersonnelList class. std::vector can grow dynamically at runtime, using its push_back() method, e.g.
#include <vector> // for std::vector
class Employee
{
....
};
class PersonnelList
{
public:
PersonnelList()
{
// Nothing to do - vector is initialized empty
}
// Get current employee count
size_t Count() const
{
return m_employees.size();
}
// Add a new employee to the personnel
void AddEmployee(const Employee& newEmployee)
{
m_employees.push_back(newEmployee);
}
private:
std::vector<Employee> m_employees;
};
No need to use raw pointers or something similar: robust RAII STL container classes make your code simpler.
I have a structure as
struct Employee
{
char uName [255];
struct Employee * next;
struct Employee * prev;
};
All i want to allocate memory of 100 stucture objects at a time and then use them one by one i making a linked list.If the memory is consumed fully then again i want to allocate 100 object memory
I am doing the allocation as
struct Employee * chunk=new struct Employee[100];
Now when i want to add a new node to a linked list i want to take objects from this already allocated memory.Can somebody tell how to achieve this
Employee * pEmployeeData=NULL;
for(long int i=1;i<=100;i++)
{
pEmployeeData=EmployeePool+i;
pEmployeeData->next=NULL;
pEmployeeData->prev=NULL;
InsertAtEnd(pEmployeeData);
}
where InsertAtEnd inserts the node at the end of the linked list.Please tell how to achieve this
I would strongly suggest that you don't try to reinvent the wheel by writing your own linked list, instead have a look at the C++ standard library which contains ready-made container types available for you to use. (for example std::vector and std::list).
Container types exist in the C++ standard library, and are used for storing collections of data/objects. for example, you could do something along the lines of
#include <iostream>
#include <vector>
#include <string>
struct Employee
{
std::string name;
int id;
};
int main()
{
std::vector<Employee> my_employees;
Employee fred = { "Fred", 1 };
Employee bob = { "Bob", 2 };
my_employees.push_back( fred );
my_employees.push_back( bob );
std::cout << my_employees[0].id << " " << my_employees[0].name << "\n"
<< my_employees[1].id << " " << my_employees[1].name << std::endl;
}
The standard containers are easy to use and to learn (You'll find plenty of internet resources which describe how to use them - and your book should also tell you!); If you're new to C++, then it's highly advisable to start out by figuring out how to use these before attempting to create your own.
You'd override the new and delete operators for your class.
new would have to look at any existing pools and see if there were any free objects, and if there weren't, it would then need to allocate a pool. Then, it would return memory allocated from it.
delete would need to check the pool that the provided object was allocated in. If ANY object is still allocated in it, the pool stays, otherwise, it can be deleted.
Also, since you're using C++, consider using a full blown class (though there is very little difference)
Have a homework assignment in which I'm supposed to create a vector of pointers to objects
Later on down the load, I'll be using inheritance/polymorphism to extend the class to include fees for two-day delivery, next day air, etc. However, that is not my concern right now. The final goal of the current program is to just print out every object's content in the vector (name & address) and find it's shipping cost (weight*cost).
My Trouble is not with the logic, I'm just confused on few points related to objects/pointers/vectors in general. But first my code. I basically cut out everything that does not mater right now, int main, will have user input, but right now I hard-coded two examples.
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Package {
public:
Package(); //default constructor
Package(string d_name, string d_add, string d_zip, string d_city, string d_state, double c, double w);
double calculateCost(double, double);
~Package();
private:
string dest_name;
string dest_address;
string dest_zip;
string dest_city;
string dest_state;
double weight;
double cost;
};
Package::Package()
{
cout<<"Constucting Package Object with default values: "<<endl;
string dest_name="";
string dest_address="";
string dest_zip="";
string dest_city="";
string dest_state="";
double weight=0;
double cost=0;
}
Package::Package(string d_name, string d_add, string d_zip, string d_city, string d_state, string r_name, string r_add, string r_zip, string r_city, string r_state, double w, double c){
cout<<"Constucting Package Object with user defined values: "<<endl;
string dest_name=d_name;
string dest_address=d_add;
string dest_zip=d_zip;
string dest_city=d_city;
string dest_state=d_state;
double weight=w;
double cost=c;
}
Package::~Package()
{
cout<<"Deconstructing Package Object!"<<endl;
delete Package;
}
double Package::calculateCost(double x, double y){
return x+y;
}
int main(){
double cost=0;
vector<Package*> shipment;
cout<<"Enter Shipping Cost: "<<endl;
cin>>cost;
shipment.push_back(new Package("tom r","123 thunder road", "90210", "Red Bank", "NJ", cost, 10.5));
shipment.push_back(new Package ("Harry Potter","10 Madison Avenue", "55555", "New York", "NY", cost, 32.3));
return 0;
}
So my questions are:
I'm told I have to use a vector
of Object Pointers, not Objects.
Why? My assignment calls for it
specifically, but I'm also told it
won't work otherwise.
Where should I be creating this
vector?
Should it be part of my Package
Class? How do I go about adding
objects into it then?
Do I need a copy constructor? Why?
What's the proper way to deconstruct
my vector of object pointers?
Any help would be appreciated. I've searched for a lot of related articles on here and I realize that my program will have memory leaks. Using one of the specialized ptrs from boost:: will not be available for me to use. Right now, I'm more concerned with getting the foundation of my program built. That way I can actually get down to the functionality I need to create.
Thanks.
A vector of pointers can be reused for storing objects of sub-classes:
class Person
{
public:
virtual const std::string& to_string () = 0;
virtual ~Person () { }
};
class Student : public Person
{
const std::string& to_string ()
{
// return name + grade
}
};
class Employee : public Person
{
const std::string& to_string ()
{
// return name + salary
}
};
std::vector<Person*> persons;
person.push_back (new Student (name, grade));
person.push_back (new Employee (name, salary));
person[0]->to_string (); // name + grade
person[1]->to_string (); // name + salary
Ideally the vector should be wrapped up in a class. This makes memory management easier. It also facilitates changing the support data structure (here an std::vector) without breaking existing client code:
class PersonList
{
public:
Person* AddStudent (const std::string& name, int grade)
{
Person* p = new Student (name, grade);
persons.push_back (p);
return p;
}
Person* AddEmployee (const std::string& name, double salary)
{
Person* p = new Employee (name, salary);
persons.push_back (p);
return p;
}
~PersonList ()
{
size_t sz = persons.size ();
for (size_t i = 0; i < sz; ++i)
delete persons[i];
}
private
std::vector<Person*> persons;
};
So we can re-write our code as:
{
PersonList persons;
Person* student = persons.AddStudent (name, grade);
Person* employee = persons.AddEmployee (name, salary);
student.to_string ();
employee.to_string ();
} // The memory allocated for the Person objects will be deleted when
// `persons` go out of scope here.
Getting familiar with the Rule of Three will help you decide when to add a copy constructor to a class. Also read about const correctness.
Question 1:
You mentioned inheritance. Since inherited objects often need more bytes of storage, they don't fit into the place of a base object. If you try to put them in, you get a base object instead. This is called object slicing.
Question 2:
Design first, before you write code. There are a bunch of possible solutions.
For a start you can keep it in main(), but later you will be forced to make a class like PackageContainer for holding your objects.
Question 3 + 4:
You need a copy constructor, an assignment operator= and a destructor, when a class object owns dynamically allocated objects (the Rule of the Big Three). So a PackageContainer will probably need them.
You create objects dynamically using new Object(..). You are responsible for destroying them and for giving their memory back to the system immediately before your vector of pointers is destroyed:
for (size_t i = 0; i < shipment.size(); ++i)
{
delete shipment[i];
}
Since working with naked pointers to dynamically allocated objects is not safe, consider using
std::vector<tr1::shared_ptr<Package> > shipment;
instead or
std::vector<std::shared_ptr<Package> > shipment;
if your compiler understands C++0x. The shared_ptr handles freeing memory for you: It implements the Rule of the Big Three for one object pointer. It should be used in production quality code.
But try to get it right with naked pointers also. I think that's what your homework assignment is about.
I'm told I have to use a vector of Object Pointers, not Objects. Why? My assignment calls for it specifically, but I'm also told it won't work otherwise.
Usually, one would avoid using vector of objects to avoid the problem of Object Slicing. To make polymorphism work You have to use some kind of pointers. I am not sure of how the classes in your assignment are aligned but probably you might have Inheritance there somewhere and hence if vector is storing objects of Base class and you insert objects of Derived class in it then it would cause the derived class members to slice off.
The Best solution will be to use a smart pointer instead of a Raw pointer. The STL has an auto_ptr, but that cannot be used in a standard container.Boost smart pointers would be a best solution but as you already said you can't use Boost So in your case you can use your compiler's implementation of smart pointers, which comes in TR1 namespace,remember though that there is some disagreement on the namespace for TR1 functions (Visual C++ puts them in std::, while GCC puts them in std::tr1::).
Where should I be creating this vector? Should it be part of my Package Class? How do I go about adding objects into it then?
Your example code already has an example of adding a pointer to Package class in a vector. In a nutshell you will dynamically allocate pointers to Package and then add them to the vector.
Do I need a copy constructor? Why?
The copy constructor generated by the compiler does member-wise copying. Sometimes that is not sufficient. For example:
class MyClass {
public:
MyClass( const char* str );
~MyClass();
private:
char* str;
};
MyClass::MyClass( const char* str2 )
{
str = new char[srtlen( str2 ) + 1 ];
strcpy( str, str2 );
}
Class::~Class()
{
delete[] str;
}
In this case member-wise copying of str member will not duplicate the buffer (only the pointer will be copied(shallow copy)), so the first to be destroyed copy sharing the buffer will call delete[] successfully and the second will run into Undefined Behavior. You need deep copying copy constructor (and assignment operator as well) in such a scenario.
When to use a custom copy constructor is best defined by the Rule Of Three:
Whenever you are writing either one of Destructor, Copy Constructor or Copy Assignment Operator, you probably need to write the other two.
What's the proper way to deconstruct my vector of object pointers?
You will have to explicitly call delete on each contained pointer to delete the content it is pointing to.
vector::erase
Removes from the vector container and calls its destructor but If the contained object is a pointer it doesnt take ownership of destroying it.
Check out this answer here to know how to corrctly delete a vector of pointer to objects.