C++ newbie: Operation of make_shared - c++

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

Related

Pointer to object and destructor

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;
}

common practice for member and parameter storage

seeking general guidance on common design practice here in > c++14 world.
Is const std::string& mName the most appropriate type here? it has the least copies, but is it good style?
I feel like a ref implies some other alias that is or could be in unknown state at some point.
Is it best style for one to make the defensive copy? and go const std::string mName instead? or if that is the case take the copy in the parameter const std::string aName and keep the & in the member field?
whats the most common practice for parameter and member storage and what are the factors that push the decision in other ways?
class Machine {
private:
const std::string& mName;
public:
Machine(const std::string& aName) : mName(aName) {
std::cout << &aName << std::endl;
std::cout << &mName << std::endl;
std::cout << std::endl;
}
};
int main() {
std::string x = "Number 1";
std::cout << &x << std::endl;
Machine m(x);
Machine m2("Number 6");
}
EDIT *
This feels better and also eliminate extra copy on temporaries I think??
class Machine {
private:
const std::string mName;
public:
Machine(const std::string&& aName) : mName(aName) {
std::cout << "1:: " << &aName << std::endl;
std::cout << "1:: " << &mName << std::endl;
}
Machine(const std::string& aName) : mName(aName) {
std::cout << "2:: " << &aName << std::endl;
std::cout << "2:: " << &mName << std::endl;
}
const std::string& name() const {
return mName;
}
};
int main() {
std::string x = "Number 1";
std::cout << &x << std::endl;
Machine m(x);
Machine m2("Number 6");
}
If you're going to store the constructor parameter in your object, then take the object by value. If the caller passes an rvalue, it will be move constructed in. If the user passes an lvalue, you were going to have to create a copy when you copy it into your object, anyhow, so just do it a step earlier.
This results in the cleanest, easiest to understand code:
class Machine {
private:
const std::string mName;
public:
Machine(const std::string aName) : mName(std::move(aName)) {
std::cout << "1:: " << &aName << std::endl; // this has been moved out of...
std::cout << "1:: " << &mName << std::endl;
}
const std::string& name() const {
return mName;
}
};
int main() {
Machine m(function_that_returns_a_string()); // move constructed all the way in - no copies made
string s;
Machine m2(s); // only one copy is made - when calling constructor, but it's then move constructed into the object
}
There are times when objects are still too expensive to move construct, at which point making two versions taking an rvalue and lvalue reference will be a win, but for most cases, the style above is the best approach.

how to copy part of char buffer to std::string?

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

c++ inheritance Building method

I have a question about building a method :
virtual std::string getPerson() const;
I have a child class Player and a the parent is Person.
Class Player :
class Player : public Person {
public:
Player(const std::string& p_name,const std::string& p_lastname, const int& p_age, const std::string& p_position);
virtual ~Player();
virtual Person* clone() const;
std::string getPosition() const;
virtual std::string getPerson() const;
private:
std::string m_position;
};
Class Person :
class Person {
public:
Person(const std::string& p_name,const std::string& p_lastname, const int& p_age);
virtual ~Person();
virtual std::string getPerson() const;
std::string getName() const;
std::string getLastName() const;
int getAge() const;
private:
std::string m_name;
std::string m_lastname;
int m_age;
};
When I try to add this in Player :
std::string Player::getPerson()
{
ostringstream os;
os << "Name :" << getName() << "\n";
os << "LastName :" << getLastName()() << "\n";
os << "Age :" << getAge()() << "\n";
os << "Position :" << getPosition();
return os.str();
}
I get Member declaration not found
I can't get it to work I would need to print something like this :
Name : John
Lastname : Smith
Age : 22
Position : Goalie
You missed the const at the end of the function signature. This should work:
std::string Player::getPerson() const
{
ostringstream os;
os << "Name :" << getName() << "\n";
os << "LastName :" << getLastName()() << "\n";
os << "Age :" << getAge()() << "\n";
os << "Position :" << getPosition();
return os.str();
}
But please mind what I said in the comment and change the function's name, or even better, make your class work with std::ostream by means of overloading operator<<.
Simple thing:
std::string getPerson() const;
is not the same as:
std::string getPerson();
If you can use c++11 use the override keyword, that protects you from such kind of mistakes. In your case the compiler detects the problem. But if you have other variants you maybe declare a new method instead of overloading!

Polymorphism vector in C++

I am trying to do a polymorphism in C++ language. My parent class is Person then there is a derived class called Student. Here is my Person.h and .cpp:
class Person
{
public:
Person(string name);
virtual void display() const;
string get_name() const;
void set_name(string name);
string get_birthDay() const;
void set_birthDay(string birthDay);
private:
string name;
string birthDay;
};
.cpp:
Person::Person(string name)
{
this->name = name;
}
string Person::get_name() const
{
return name;
}
void Person::set_name(string name)
{
this->name = name;
}
string Person::get_birthDay() const
{
return birthDay;
}
void Person::set_birthDay(string birthDay)
{
this->birthDay = birthDay;
}
void Person::display() const
{
cout << get_name() << " " << get_birthDay() << endl;
}
And this is my Student.h and .cpp:
class Student : public Person
{
public:
Student(string name, string major);
virtual void display() const;
string get_major() const;
void set_major(string major);
private:
string major;
};
.cpp:
Student::Student(string name, string major)
:Person(name)
{
this->major = major;
}
string Student::get_major() const
{
return major;
}
void Student::set_major(string major)
{
this->major = major;
}
void Student::display() const
{
cout << get_name() << " " << get_major() << endl;
}
All working perfectly until my main method. Here is my main method:
int main()
{
vector <Person*> person_list;
person_list.push_back(Student("Student","IT"));
person_list.push_back(Instructor("Instrructor", 2500));
for(int count=0; count< person_list.size(); count++)
{
cout << person_list[count]->display() << endl;
}
system("Pause");
return 0;
}
I got an error at the push_back and cout there. The error message for push_back to vector is: no instance of overloaded function matches the argument list. As for the cout, no operator matches the operands. I have no idea why. Anybody can help me fix it?
Thanks in advance.
Your person_list stores pointer but you pushed object instead:
To fix your issue:
person_list.push_back(new Student("Student","IT"));
//^^^^
person_list.push_back(new Instructor("Instrructor", 2500));
To store pointer in STL container, better use smart pointer:
#include <memory>
std::vector <std::unique_ptr<Person>> person_list;
You will need to push back a pointer to Student; i.e. use
person_list.push_back(new Student("Student","IT")); etc.
But, you will need to be very very careful with memory, since you will need to delete the memory you've allocated; the vector will not do this for you when it destructs.
Consider using a smart pointer instead.
cout << person_list[count]->display() << endl;
The display() function is of void return type. You cannot output that.
As for the push_back: like the others said, if you've got a vector of pointers, you need to push_back a pointer, not the object.