0

I am new to C++ (more of a java guy). I am trying to teach myself about C++ pointers. Here I've created two classes, Person (The base class), and the Student (Derived class).

I tried to put Student objects in an unordered_map<string, Person>. But met an error.

This is my code:

class Person { protected: string name; int age; public: int getAge() { return age; } string getName() { return name; } }; class Student : public Person { private: string grade; public: Student(string const &name, int const &age, string const &grade) { this -> name = name; this -> age = age; this -> grade = grade; } int getAge(); }; 

Here's my main function:

int main() { unordered_map<string, Person *> students; Student s("Sam", 26, "A"); Person *p; p = &s; students.insert(p -> getName(), p); return 0; } 

This is just a part of the code, and I know it looks foolish. But I'm just learning about pointers

I have included <iostream> and <unordered_map> libraries and using namespace std here.

Error message is so long. Can someone point out the error I made here ? Or, should I post that long error message also ? Thanks in advance.

6
  • 1
    you can use students.insert({p -> getName(), p}); Commented Dec 7, 2016 at 11:54
  • "Error message is so long." And the answer is "too large to fit in the margin" :-) Commented Dec 7, 2016 at 11:57
  • But, what's wrong with my code ? Commented Dec 7, 2016 at 11:57
  • @Jarod42 It's rude to post sarcastic comments, while someone is asking for help ! Commented Dec 7, 2016 at 11:59
  • 1
    @ThisaruGuruge: I mean help us to help you. Providing (part of) the error message can help to have answer. insert take a std::pair parameter, so you have to construct pair or use other method as emplace. Commented Dec 7, 2016 at 12:02

3 Answers 3

2

I am more of a java guy.

Here's what you need to know:

Pointers

Person* is a pointer to a person - a pointer simply carries the address of an object in memory. It's as low level as you can get. It's equivalent to using an address register or index register in assembly language. It carries no information about object lifetime and does not influence object lifetime in any way. It is 100% abusable. Use with care, if ever.

Shared references

// java code var x = new Y(); var y = x; // equivalent c++ auto x = std::make_shared<Y>(); auto y = x; 

If you want java-like behaviour, then std::shared_ptr<Person> is equivalent to a java object reference. It shares ownership of the person and allows (actually in c++ mandates) that the Person is destroyed when all of the shared_ptrs have gone out of scope or have been reset.

Unique reference with lifetime control

Between the two is a std::unique_ptr<Person> which will cause the automatic destruction of the Person when the one and only unique_ptr is destroyed or reset. You cannot copy a std::unique_ptr so it can't be used to share references to an object. It can however, be converted to a shared_ptr (this implicitly empties the unique_ptr).

Weak references

Then there is a std::weak_ptr<Person> which is the weak counterpart to a std::shared_ptr<Person>. It cannot be de-referenced directly but must first be converted to a shared_ptr with the lock() method. This provides an atomic 'test for existence and lock into place' operation. We use it to resolve or avoid resource leaks caused by circular references (which java claims not to have on account of garbage collection).

Lifetime differences between Java and C++

In Java, when there are no more reachable references to an object, it becomes a candidates for garbage collection. At some point in the future, it may or may not be recovered.

C++ is different and more predictable. When the unique_ptr or the last shared_ptr controlling an object's lifetime is reset, that object's destructor will be executed immediately and in the same thread. It's completely sequential. This gives rise to the possibility of RAII, and allows us to use object lifetimes to cause code to execute no matter what the execution path.

This is also arguably why there is no need for finally in c++. Resource cleanup goes in the destructors of resource owners.

Sign up to request clarification or add additional context in comments.

1 Comment

Wow. Thank you for the more detailed and explained answer. This is a great help !
1
int main() { unordered_map<string, Person *> students; Student s("Sam", 26, "A"); Person *p; p = &s; pair<string, Person*> item("key", p); students.insert(item); return 0; } 

Comments

1

Your code looks ok, except for one line:

students.insert(p -> getName(), p); 

Here you probably meant that you want to place p to the cell p->getName(), but, unfortunately, std::unordered_map::insert has no instance to take a key and a value as two arguments. Passing them as one argument or using operator[] should help:

students[p->getName()] = p; students.insert({p->getName(), p}); students.insert(std::make_pair(p->getName(), p)); 

I personally would select first option as more readable, if possible.

UP: As @Jarod42 commented, the first option here requires the value type to be default constructible, which is not always an option.

3 Comments

The first option requires that value is default constructible, which is not always the case. emplace is an other possibility.
@Jarod42 Thank you, it's an important clarification. Will add to the answer.
Thanks @alexeykuzmin0

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.