I try to store instances of class Person in std::list Users. Before putting each instance to Users I want to copy first 10 bytes from buf to std::string Name. How can I do that?
class Person {
public:
Person(){ std::cout << "Constructing Person " << std::endl;}
private:
std::string Name;
};
int main() {
unsigned char buf[1024];
std::list<Person> Users;
Person ps;
Users.push_back(ps);
return 0;
}
You'll need to change your constructor for doing this:
class Person {
public:
Person(const char* buf_, size_type size_)
: name(buf_,size_) {
std::cout << "Constructing Person " << std::endl;
}
// ....
};
and in main() write
Person ps(buf,10);
You could provide an appropriate constructor for Person.
Person(std::string Name) : Name(std::move(Name)) {}
Definition of a Person would be
Person ps(std::string(buf, 10));
Or write directly:
Users.emplace_back( std::string(buf, 10) );
Related
I am trying to understand why my code doesn't use destructor of class Name. In fact I write two classes. First one called Name and a second called Person that have a pointer to object Name. What I don't understand is why the program doesn't called to the destructor of Name, because I think when I write "new" I create a new object so it has to call to the destructor of class Name before closing program.
Can you explain what wrong in my understanding. Thanks !
class Name
{
private:
string name;
public:
Name(string name) : name(name) { cout << "Hello " << name << endl; }
~Name() { cout << "See you soon " << name; }
};
class Person
{
private:
Name* myname;
public:
Person(string name) { myname = new Name(name); }
~Person() { cout << "Exit" << endl; }
};
int main()
{
Person("Marc");
Person("Alex");
}
You are creating a memory leak here, because you create a new instance of Name here
Person(string name) { myname = new Name(name); }
but you never delete it. This is the reason why the destrcutor of Name is never called.
To avoid this you can use an std::unique_ptr or an std::shared_ptr, which will automatically handle the lifetime of such an object.
std::unique_ptr<Name> myname;
Person(string name) { myname = std::make_unique<Name>(name); }
An alternative is to delete the object in your destructor, but in C++ you should avoid direct handling of dynamic raw pointers.
#include <iostream>
#include <memory>
class Name
{
private:
std::string name;
public:
Name(std::string name) : name(name) { std::cout << "Hello " << name << std::endl; }
~Name() { std::cout << "See you soon " << name << std::endl; }
};
class Person
{
private:
std::unique_ptr<Name> myname;
public:
Person(std::string name) { myname = std::make_unique<Name>(name); }
~Person() { std::cout << "Exit" << std::endl; }
};
int main(int argc, char **argv)
{
Person("Marc");
Person("Alex");
return 0;
}
As myname object in Person's class is a pointer. For every pointer there must be a delete statement to deallocate the memory.
Replace Person's class Destructor as:
~Person() {
cout << "Exit" << endl;
delete myname;
}
I'm still learning how the abstract classes work and I want know if I'm on the right track or not.
This is my simplified program :
class CPerson
{
public:
CPerson() = default;
virtual int getMat() = 0;
};
class CStudent : public CPerson
{
public:
CStudent() = default;
CStudent(int MatriculationNr) { this->MatriculationNr = MatriculationNr;}
int getMat() { return MatriculationNr;}
private:
int MatriculationNr;
};
class CTeacher : public CPerson
{
public:
CTeacher() = default;
int getMat(){ return 0;}
private:
std::string name;
};
int main()
{
std::vector<CPerson*> test;
test.push_back(new CStudent(9898));
CTeacher *a = new CTeacher();
return 0;
}
In class CTeacher, I don't have the same private variable like CStudent (MatriculationNr) so I returned 0. The program is working normally. But is what I'm doing here correct or not?
Another question related to the abstract classes : Assuming we use virtual int& getMat() = 0; (with a reference), what should we return in CTeacher class? 0 will not work in this case, right?
Should we initalize a variable with 0 so that we can return it in this function, or is there a better implementation?
Below code sample should answer your question in a rather modern C++ way.
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// I have added a `std::string name` to the CPerson class and
// a `std::string subject` to the CTeachers class
// so both derived classes, CStudent and CTeacher have a name
// of the person involved and each derived class has
// something only it needs, MatrikulationNr for CStudent and
// Subject of teaching for CTeacher in order to deliver a more
// complete and more clearifying answer.
class CPerson {
int dummyMatriculationNr{ 0 };
std::string dummySubject{ "noTeacher" };
protected:
std::string name;
public:
std::string getName() { return name; }
virtual int& getMat() { return dummyMatriculationNr; }
virtual std::string getSubject() { return dummySubject; }
};
class CStudent : public CPerson {
int MatriculationNr{ 0 };
public:
CStudent() = delete; // we dont want anyone using this constructor
explicit CStudent(std::string name, int MatriculationNr) :
MatriculationNr{ MatriculationNr } {
this->name = name;
}
int& getMat() { return MatriculationNr; }
};
class CTeacher : public CPerson {
std::string subject{ "" }; // Subject of teaching
public:
CTeacher() = delete;
explicit CTeacher(std::string name, std::string subject) :
subject{ subject } {
this->name = name;
}
std::string getSubject() { return subject; }
};
int main() {
std::vector<std::unique_ptr<CPerson>> vp;
vp.push_back(std::make_unique<CStudent>("aStudentsName", 8989 ));// or emplace_back
vp.push_back(std::make_unique<CTeacher>("aTeachersName", "mathematics"));
for (auto& e : vp)
std::cout << "Name: " << e->getName() << " MatrNo: " << e->getMat()
<< " TeachingSubject: " << e->getSubject() << std::endl;
}
I hope above sample answers your question. However, using the keyword virtual creates a virtual function table, often called vtable, at runtime which costs performance and is considered not to be high performance computing anymore.
Its also confusing to have a getMat() function available in all derived classes when you need it only in one, the CStudents derived class. Although meaningless in any other class, this function still returns some dummy value there. That can be irritating. Same for the getSubject() function in CTeacher. See the output:
Name: aStudentsName MatrNo: 8989 TeachingSubject: noTeacher
Name: aTeachersName MatrNo: 0 TeachingSubject: mathematics
Consider to solve your question without any keyword virtual and having getMat() and int MatriculationNr in CStudents only and not in the base class at all. I know it is tempting to use virtual but its something to rather avoid as long as possible. For example, MFC, Microsoft Foundation Classes, the maybe biggest class inheritance project ever written, did not use virtual at all!
Consider the following code as an example:
#include <iostream>
#include <string>
#include <vector>
#include <variant>
// a code version without virtual
class CPerson {
protected:
std::string name;
public:
std::string getName() { return name; }
};
class CStudent : public CPerson {
int MatriculationNr{ 0 };
public:
CStudent() = delete; // we dont want anyone using this constructor
explicit CStudent(std::string name, int MatriculationNr) : MatriculationNr{ MatriculationNr } {
this->name = name;
}
int& getMat() { return MatriculationNr; }
};
class CTeacher : public CPerson {
std::string subject{ "" }; // Subject of teaching
public:
CTeacher() = delete;
explicit CTeacher(std::string name, std::string subject) : subject{ subject } {
this->name = name;
}
std::string getSubject() { return subject; }
};
int main() {
std::vector<CStudent> vs; // auto-deleted through RAII
std::vector<CTeacher> vt; // and good for serialisation and or database communication
vs.push_back(CStudent{ "aStudentsName", 9898 });
vt.push_back(CTeacher{ "aTeachersName", "mathematics" });
for (auto s : vs)
std::cout << s.getName() << " " << s.getMat() << std::endl;
for (auto t : vt)
std::cout << t.getName() << " " << t.getSubject() << std::endl << std::endl;
// and here we are done already,
// not listing the two different types in one vector
// but just using a vector for each derived class
//
// but lets try put them now into one vector
// using a more modern way through std::variant
// which keps all data in the vector and not only the
// CPerson part.
std::vector<std::variant<CStudent, CTeacher>> people;
// we could, for example, copy from above vectors
for (auto e : vs)
people.push_back(e);
for (auto e : vt)
people.push_back(e);
// we could insert new ones
people.push_back(CStudent { "aStudentsName1", 9899 });
people.push_back(CTeacher { "aTeachersName1", "physics" });
// and take that vector apart again
std::cout << std::endl << "Output from vector of variant:" << std::endl;
for (auto& e : people)
if (std::holds_alternative<CStudent>(e)) {
CStudent& s = std::get<CStudent>(e);
std::cout << s.getName() << " " << s.getMat() << std::endl;
}
else if (std::holds_alternative<CTeacher>(e)) {
CTeacher& s = std::get<CTeacher>(e);
std::cout << s.getName() << " " << s.getSubject() << std::endl;
}
}
There are numerous ways to achieve the goal to avoid virtual and I hope you did enjoy the above.
Everything in the code above seems alright. Just make sure to delete both objects after using them (the CStudent and the CTeacher).
I am new to C++. Can someone please let me know what is wrong with the following code segment -
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
std::map<std::string, std::shared_ptr<Person>> plist;
std::string namestr = "Hoo";
std::shared_ptr<Person> r1(std::make_shared<Person>("Dull"));
plist.insert({"Key1", r1});
auto u = plist.find("Key1");
shared_ptr<Person> v = u->second;
v->dump();
plist.erase(plist.find("Key1"));
My intention is to create a database of Person objects and I was trying to use shared_ptr for that.
v->dump() causes a segmentation fault. However, if I use the 'namestr' variable instead of the string literal "Dull" then the v->dump() appears to work correctly, i.e. the following -
std::shared_ptr<Person> r1(std::make_shared<Person>(namestr));
Also, the following way also seems to work even though I use a string literal in the intializer.
std::shared_ptr<Person> r1(new Person("Dull"));
Pointers to the mistake I am making would be much appreciated!
class Person {
public:
const std::string& name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
this is storing a reference to a string whose life time is not guaranteed. You should do
class Person {
public:
const std::string name;
Person(const std::string& s): name(s) {}
void dump(void) const {
cout << name << endl;
//cout << &name << endl;
}
};
You code fails because "Dull" created a temporary string that went out of scope immediately
Read the comments too.
Basically, I am trying to figure out object constructors, destructor, and classes. I created a class with a few public member variables, and a few private member variables. At this point I am only utilizing the public members within my code.
My question is, to put it quite simply, how do I utilize the constructor, destructor, and print off the objects info to the console.
Thanks.
#include <iostream>
// Class -> NPC
// Contains generic stats for an NPC in a game
class NPC
{
public:
char name;
int age;
char favoriteItem;
private:
char quest;
char nemesis;
int karma;
}
// Object Constructor
NPC::NPC (char newName, int newAge, char newFavoriteItem)
{
name = newName;
age = newAge;
favoriteItem = newFavoriteItem;
}
// Object Deconstructor
NPC::~NPC()
{
// Do nothing
}
// Here I would like to create a new NPC, bob, with a name of "Bob", age of 28, and his favorite items being a Sword
// Next, I attempt to use this information as output.
int main()
{
NPC bob("Bob",28, "Sword");
std::cout << bob << std::endl;
}
Fixed the char (only one character) to std::string. I added initialization list and std::ostream &operator << operator.
http://en.cppreference.com/w/cpp/language/default_constructor
#include <iostream>
#include <memory>
#include <string.h>
class NPC
{
public:
std::string name;
int age;
std::string favoriteItem;
NPC(std::string const& name, int age, std::string favoriteItem)
: name(name), age(age), favoriteItem(favoriteItem)
{};
private:
char quest;
char nemesis;
int karma;
};
std::ostream &operator << (std::ostream &os, NPC const& npc)
{
os << npc.name << " " << npc.age << " " << npc.favoriteItem << "\n";
return os;
};
int main()
{
NPC npc("Bob", 28, "Sword");
std::cout << npc;
return 0;
}
I have this code:
#include <iostream>
#include <string>
#include <cstring>
class Animal
{
public:
Animal(const std::string &name) : _name(name)
{
}
virtual void Print() const = 0;
virtual ~Animal() {}
protected:
std::string _name;
};
class Dog : public Animal
{
public:
Dog(const std::string &name, const std::string &dogtype) : Animal(name), _dogtype(dogtype)
{
Print();
}
void Print() const
{
std::cout << _name << " of type " << _dogtype << std::endl;
}
private:
std::string _dogtype;
};
class Cat : public Animal
{
public:
Cat(const std::string &name, int weight) : Animal(name), _weight(weight)
{
Print();
}
virtual void Print() const
{
std::cout << _name << " of weight " << _weight << std::endl;
}
virtual ~Cat(){}
private:
int _weight;
};
class Tiger : public Cat
{
public:
Tiger(const std::string &name, int weight, double speed) : Cat(name, weight), _speed(speed)
{
Print();
}
void Print() const
{
std::cout << _name << " speed " << _speed << std::endl;
}
virtual ~Tiger(){std::cout << "Tiger's dtor" << std::endl;}
private:
int _speed;
};
int main()
{
Animal *a = new Tiger("theRealKing", 3, 40.5);
Cat *c = new Cat("silvester", 4);
memcpy(c, a, sizeof(Cat));
c->Print(); /// ------------------------
delete a;
delete c;
return 0;
}
in the line : c->Print():
the line before that c became a tiger so why does it print me this line :
Ross with speed 135081
insted of
Ross with speed 3
why there is a memory problem ?
why does it call the print method of tiger and not of cat ?
It doesn't work together.
Using memcpy on these objects produces undefined behavior, the Standard permits anything to happen.
It isn't inheritance per se that is causing you problems, but the presence of virtual member functions or custom constructor/destructor. These make your objects lose the trivially-copyable classification that is required when using memcpy.
Your class isn't trivially-copyable for a second reason -- it contains a member of type std::string which is not trivially-copyable.
In practical terms, when you perform a bitwise copy of a std::string subobject, you end up with two pointers to the same memory, and both string objects will try to free this pointer. That will crash your program. If using memcpy on a v-table hasn't done so earlier.
But when you mix in optimizations, even weirder things can happen. That's what undefined behavior means.
You should avoid using memcpy for objects in c++, use the copy constructor instead.