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.
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.
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;
}
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.
Related
class Student {
private:
int age;
public:
char *name;
Student(int age,char*name) {
this->age=age;
this->name=new char[strlen(name)+1];
strcpy(this->name,name);
}
Student(Student const &s1) {
this->age=s1.age;
this->name=new char[strlen(s1.name)+1];
strcpy(this->name,s1.name);
s1.name[0]='x';
}
void display() {
cout<<age<<" "<<name<<endl;
}
};
int main() {
char name[]="abcd";
Student s1(10,name);
s1.display();
Student s2(s1);
s2.name[0]='x';
s1.display();
s2.display();
}
I have passed s1 as a constant reference but I am able to change s1.name[0] and the program compiles successfully. Why I am able to change s1.name[0]?enter image description here
You did not modify s1. You modified some unrelated memory block (allocated by new) , to which s1 holds a pointer. In C++ there is no special relationship between a raw pointer and any memory block it might happen to be pointing to.
If you use std::string instead of raw pointers and manual memory management then this problem will not arise.
As others have already said this is because s1 is const, so you cannot modify the pointer s1.name. However, the memory s1.name is pointing at is not const.
If you really cannot use std::string, you might want to have a look at std::experimental::propagate_const. This is a wrapper for any pointer type, in your case a raw pointer, that will, as the name suggests, propagate its constness to the memory it points at.
But as I can hardly imagine any circumstances where you are not able/allowed to use an std class (string), but an std::experimental class would be ok, this is likely not an option for you. However, you might get inspired by the idea and write your own string class.
Note in case you are not aware: you are missing a corresponding delete for your new. std::string would do that for you. So, if you write your own string class, make sure that one also does that.
I seem to have an issue with dynamic memory allocation.
Below you'll see a derived class that contains a pointer for a name variable that will be dynamically allocated using the void name(const char* name) method. The function is run by the Product constructor, which sets a name for the product class when the object is created. Here's the class:
namespace sict {
class Product :public Streamable {
char* name_;
public:
Product(const char* name);
virtual ~Product();
void name(const char* name);
}
And here's the name function itself, along with the one argument constructor:
void sict::Product::name(const char * name) {
int g = strlen(name);
name_ = new char[g];
strncpy(name_, name, g);
name_[g] = 0;
}
Product::~Product() {
delete [] name_;
name_ = nullptr;
}
To me this code seems capable enough of created the object then destroying it peacefully whenever it exits the scope of the function it's running in. However, when the function ends and the destructor runs, the program freezes/crashes at delete [] name_. Running the program on Visual Studio's compiler seems to yield no particular errors (other than the program freezing), but the gcc compiler detects some sort of heap corruption. Would anybody know why this is happening?
I'm not sure why Sean Cline didn't post his comment as an answer, but Sean is correct.
name_ is given g elements and then name_[g] is set to zero, but name_[g] is one past the end of the array. Either use name_ = new char[g+1]; or name_[g-1] = 0; so that you don't go past the end of the array.
Also, as several comments point out, any time you have a class that allocates memory dynamically, make sure you define the copy constructor, the assignment operator, and the destructor. If you miss one, the default implementation will perform a shallow copy, which can cause headaches for you.
A shallow copy is when the pointer is copied instead of the data it points to. In your case, if an object of this class is ever copied or assigned, you end up with two objects pointing to the same data on the heap, and they would both try to delete it when they run their destructors.
For more information on those functions, see the Rule of Three
i dont really get the fields of the template std::vector, the first one specifies the type, for example a class, but i dont get the allocator, pointer and reference variables.
i will provide a simple example, i want to use a vector of class person, so i have to say to the template vector: hey, store me some person's, but i also have to tell the vector how to allocate that class. (1)How would a correct syntax be for that example?
some code to start with:
side note, in the person's constructor,c(2)should i use date*?
class date
{
public:
int m_nMonth;
int m_nDay;
int m_nYear;
int getMonth(return m_nMonth;)
int getDay(return m_nDay;)
int getYear(return m_nYear;)
void setDate(int month, int day, int year)
{
m_nMonth=month;
m_nDay=day;
m_nYear=year;
}
date()
{
setDate(0,0,0);
}
date(int month, int day, int year)
{
setDate(month,day,year);
}
void printDate()
{
printf("%d/%d/%d", m_nMonth, m_nDay, m_nYear);
}
}
class person
{
public:
int m_nID;
char m_sName[128];
char m_sSurname[128];
date m_cBirthDay;
void setName(const char* name)
{
strncpy(m_sName, name, 127);
m_sName[127]= '\0';
}
void setSurname(const char* surname)
{
strncpy(m_sSurname, surname, 127);
m_sName[127]= '\0';
}
void setBirthDay(date* bday);
{
m_cBirthDay.date(bday.getMonth(), bday.getDay(), bday.getYear)
}
person(int id, const char* name, const char* surname, date bday)/*should it be date* bday? why?*/
{
m_nID=id;
setName(name);
setSurname(surname);
setBirthDay(bday);
}
}
i suppose you have to declare a function inside class person, called allocator, that is whats passed as second argument when you call, (3)how would that allocator function be defined?:
vector <person*, /*some allocator call*/> ImAVector;
then, (4)how could i push something in the vector, (5)would this work?:
person* someperson;
someperson.person(/*arguments*/);
ImAVector.push_back(someperson);
(6)how could i retrieve the pointer to a particular instance? (7)can i use the iterator to do something like this?:
//(6)
person* = ImAVector[someIterator];
//and then (7)
ImAVector[someIterator].setName(someConstCharPointer);
string* something = person.getName();
also, (8)does the allocator have anything to do with the constructor? (9)its common procedure to fill your class's fields right after allocating the instance of the class? (10)can an allocator call a constructor?
And the last questions: (11)what is the reference field, the pointer field, and their const counterparts?
I know its a lot to write, but ive spent the last two days searching for examples without success, so it would be nice if someone shed some light into this rarely discussed topic, ive numerated all questions for an easy response.
I appreciate any answers :)
How would a correct syntax be for that example?
Unless you have a good reason for storing pointers, don't. Then you just declare
std::vector<person> people;
// In C++11, you can create people in place
people.emplace_back(id, name, surname, birthday);
// Historically, you had to create a person and copy it in
people.push_back(person(id, name, surname, birthday));
and all the allocation is managed for you.
Reasons for wanting pointers include:
the vector is not supposed to manage the objects. In that case, you don't need to tell the vector how to allocate them.
perhaps person is a base class and you want to store various different subtypes.
In that case, I don't think you can use an allocator to help; instead, you could store smart pointers to automatically delete the objects when the pointer is removed from the container:
std::vector<std::unique_ptr<person>> people;
people.push_back(std::unique_ptr<person>(new person(id, name, surname, birthday)));
The alternative is to juggle raw pointers and try to delete the objects at the right time; but life's too short for that nonsense.
(2)should i use date*?
No. For a large or complicated class, it might be beneficial to pass a const reference, const date&; but this class is simple enough to pass by value. Passing a pointer would be weird, except in languages like C where that's the only way to pass by reference.
how could i retrieve the pointer to a particular instance?
people[index] gives a reference (not pointer) to the person with that index. If you really want a pointer for some reason, use & to take the address:
person & ref = people[index];
person * ptr = &ref;
can i use the iterator to do something like this?
No, [] is used to access by the array index, not to dereference an iterator. If you have an iterator it, then *it gives you a reference to the object.
does the allocator have anything to do with the constructor?
No, allocators are used if you have special memory-management requirements, and don't want the vector to simply allocate memory on the heap. There use is quite rare.
its common procedure to fill your class's fields right after allocating the instance of the class
It's common to initialise all the data members in the constructor, yes.
You don't need to specify anything other than the type.
vector<person> people;
people.emplace_back(/* constructor arguments for a person */); // constructs the person in place instead of copying into the vector.
person p;
p.stuff();
vector.push_back(p); // copies p into the vector
etc. Basically the defaults for allocator and the other fields are good enough, no need to specify them unless you have reason to override the default behavior. I've never had reason to do so.
I need to store a list of various properties of an object. Property consists of a name and data, which can be of any datatype.
I know I can make a class "Property", and extend it with different PropertySubClasses which only differ with the datatype they are storing, but it does not feel right.
class Property
{
Property(std::string name);
virtual ~Property();
std::string m_name;
};
class PropertyBoolean : Property
{
PropertyBoolean(std::string name, bool data);
bool m_data;
};
class PropertyFloat : Property
{
PropertyFloat(std::string name, float data);
float m_data;
};
class PropertyVector : Property
{
PropertyVector(std::string name, std::vector<float> data);
std::vector<float> m_data;
};
Now I can store all kinds of properties in a
std::vector<Property*>
and to get the data, I can cast the object to the subclass. Or I can make a pure virtual function to do something with the data inside the function without the need of casting.
Anyways, this does not feel right to create these different kind of subclasses which only differ by the data type they are storing. Is there any other convenient way to achieve similar behavior?
I do not have access to Boost.
C++ is a multi-paradigm language. It shines brightest and is most powerful where paradigms are mixed.
class Property
{
public:
Property(const std::string& name) //note: we don't lightly copy strings in C++
: m_name(name) {}
virtual ~Property() {}
private:
std::string m_name;
};
template< typename T >
class TypedProperty : public Property
{
public:
TypedProperty (const std::string& name, const T& data)
: Property(name), m_data(data);
private:
T m_data;
};
typedef std::vector< std::shared_ptr<Property> > property_list_type;
Edit: Why using std::shared_ptr<Property> instead of Property*?
Consider this code:
void f()
{
std::vector<Property*> my_property_list;
for(unsigned int u=0; u<10; ++u)
my_property_list.push_back(new Property(u));
use_property_list(my_property_list);
for(std::vector<Property*>::iterator it=my_property_list.begin();
it!=my_property_list.end(); ++it)
delete *it;
}
That for loop there attempts to cleanup, deleting all the properties in the vector, just before it goes out of scope and takes all the pointers with it.
Now, while this might seem fine for a novice, if you're an only mildly experienced C++ developer, that code should raise alarm bells as soon as you look at it.
The problem is that the call to use_property_list() might throw an exception. If so, the function f() will be left right away. In order to properly cleanup, the destructors for all automatic objects created in f() will be called. That is, my_property_list will be properly destroyed. std::vector's destructor will then nicely cleanup the data it holds. However, it holds pointers, and how should std::vector know whether these pointers are the last ones referencing their objects?
Since it doesn't know, it won't delete the objects, it will only destroy the pointers when it destroys its content, leaving you with objects on the heap that you don't have any pointers to anymore. This is what's called a "leak".
In order to avoid that, you would need to catch all exceptions, clean up the properties, and the rethrow the exception. But then, ten years from now, someone has to add a new feature to the 10MLoC application this has grown to, and, being in a hurry, adds code which leaves that function prematurely when some condition holds. The code is tested and it works and doesn't crash - only the server it's part of now leaks a few bytes an hour, making it crash due to being out of memory about once a week. Finding that makes for many hours of fine debugging.
Bottom line: Never manage resources manually, always wrap them in objects of a class designed to handle exactly one instance of such a resource. For dynamically allocated objects, those handles are called "smart pointer", and the most used one is shared_ptr.
A lower-level way is to use a union
class Property
union {
int int_data;
bool bool_data;
std::cstring* string_data;
};
enum { INT_PROP, BOOL_PROP, STRING_PROP } data_type;
// ... more smarts ...
};
Dunno why your other solution doesn't feel right, so I don't know if this way would feel better to you.
EDIT: Some more code to give an example of usage.
Property car = collection_of_properties.head();
if (car.data_type == Property::INT_PROP) {
printf("The integer property is %d\n", car.int_data);
} // etc.
I'd probably put that sort of logic into a method of the class where possible. You'd also have members such as this constructor to keep the data and type field in sync:
Property::Property(bool value) {
bool_data = value;
data_type = BOOL_PROP;
}
I suggest boost::variant or boost::any. [Related question]
Write a template class Property<T> that derives from Property with a data member of type T
Another possible solution is to write a intermediate class managing the pointers to Property classes:
class Bla {
private:
Property* mp
public:
explicit Bla(Property* p) : mp(p) { }
~Bla() { delete p; }
// The standard copy constructor
// and assignment operator
// aren't sufficient in this case:
// They would only copy the
// pointer mp (shallow copy)
Bla(const Bla* b) : mp(b.mp->clone()) { }
Bla& operator = (Bla b) { // copy'n'swap trick
swap(b);
return *this;
}
void swap(Bla& b) {
using std::swap; // #include <algorithm>
swap(mp, b.mp);
}
Property* operator -> () const {
return mp;
}
Property& operator * () const {
return *mp;
}
};
You have to add a virtual clone method to your classes returning a pointer to a newly created copy of itself:
class StringProperty : public Property {
// ...
public:
// ...
virtual Property* clone() { return new StringProperty(*this); }
// ...
};
Then you'll be able to do this:
std::vector<Bla> v;
v.push_back(Bla(new StringProperty("Name", "Jon Doe")));
// ...
std::vector<Bla>::const_iterator i = v.begin();
(*i)->some_virtual_method();
Leaving the scope of v means that all Blas will be destroyed freeing automatically the pointers they're holding. Due to its overloaded dereferencing and indirection operator the class Bla behaves like an ordinary pointer. In the last line *i returns a reference to a Bla object and using -> means the same as if it was a pointer to a Property object.
A possible drawback of this approach is that you always get a heap operation (a new and a delete) if the intermediate objects must be copied around. This happens for example if you exceed the vector's capacity and all intermediate objects must be copied to a new piece of memory.
In the new standard (i.e. c++0x) you'll be able to use the unique_ptr template: It
can be used inside the standard containers (in contrast to the auto_ptr which must not be used in the standard containers),
offers the usually faster move semantics (it can easily passed around) and
takes care over the held pointers (it frees them automatically).
I see that there are lots of shots at trying to solve your problem by now, but I have a feeling that you're looking in the wrong end - why do you actually want to do this in the first place? Is there some interesting functionality in the base class that you have omitted to specify?
The fact that you'd be forced to switch on a property type id to do what you want with a specific instance is a code smell, especially when the subclasses have absolutely nothing in common via the base class other than a name (which is the type id in this case).
Starting with C++ 17 we have something called as std::variant and std::any.
std::variant
An instance of std::variant at any given time either holds a value of one of its alternative types, or in the case of error - no value.
std::any
The class any describes a type-safe container for single values of any copy constructible type.
An object of class any stores an instance of any type that satisfies the constructor requirements or is empty, and this is referred to as the state of the class any object. The stored instance is called the contained object. Two states are equivalent if they are either both empty or if both are not empty and if the contained objects are equivalent.
The non-member any_cast functions provide type-safe access to the contained object.
You can probably do this with the Boost library, or you could create a class with a type code and a void pointer to the data, but it would mean giving up some of the type safety of C++. In other words, if you have a property "foo", whose value is an integer, and give it a string value instead, the compiler will not find the error for you.
I would recommend revisiting your design, and re-evaluating whether or not you really need so much flexibility. Do you really need to be able to handle properties of any type? If you can narrow it down to just a few types, you may be able to come up with a solution using inheritance or templates, without having to "fight the language".
EDIT: I know in this case, if it were an actual class i would be better off not putting the string on the heap. However, this is just a sample code to make sure i understand the theory. The actual code is going to be a red black tree, with all the nodes stored on the heap.
I want to make sure i have these basic ideas correct before moving on (I am coming from a Java/Python background). I have been searching the net, but haven't found a concrete answer to this question yet.
When you reassign a pointer to a new object, do you have to call delete on the old object first to avoid a memory leak? My intuition is telling me yes, but i want a concrete answer before moving on.
For example, let say you had a class that stored a pointer to a string
class MyClass
{
private:
std::string *str;
public:
MyClass (const std::string &_str)
{
str=new std::string(_str);
}
void ChangeString(const std::string &_str)
{
// I am wondering if this is correct?
delete str;
str = new std::string(_str)
/*
* or could you simply do it like:
* str = _str;
*/
}
....
In the ChangeString method, which would be correct?
I think i am getting hung up on if you dont use the new keyword for the second way, it will still compile and run like you expected. Does this just overwrite the data that this pointer points to? Or does it do something else?
Any advice would be greatly appricated :D
If you must deallocate the old instance and create another one, you should first make sure that creating the new object succeeds:
void reset(const std::string& str)
{
std::string* tmp = new std::string(str);
delete m_str;
m_str = tmp;
}
If you call delete first, and then creating a new one throws an exception, then the class instance will be left with a dangling pointer. E.g, your destructor might end up attempting to delete the pointer again (undefined behavior).
You could also avoid that by setting the pointer to NULL in-between, but the above way is still better: if resetting fails, the object will keep its original value.
As to the question in the code comment.
*str = _str;
This would be the correct thing to do. It is normal string assignment.
str = &_str;
This would be assigning pointers and completely wrong. You would leak the string instance previously pointed to by str. Even worse, it is quite likely that the string passed to the function isn't allocated with new in the first place (you shouldn't be mixing pointers to dynamically allocated and automatic objects). Furthermore, you might be storing the address of a string object whose lifetime ends with the function call (if the const reference is bound to a temporary).
Why do you think you need to store a pointer to a string in your class? Pointers to C++ collections such as string are actually very rarely necessary. Your class should almost certainly look like:
class MyClass
{
private:
std::string str;
public:
MyClass (const std::string & astr) : str( astr )
{
}
void ChangeString(const std::string & astr)
{
str = astr;
}
....
};
Just pinpointing here, but
str = _str;
would not compile (you're trying to assign _str, which is the value of a string passed by reference, to str, which is the address of a string). If you wanted to do that, you would write :
str = &_str;
(and you would have to change either _str or str so that the constnest matches).
But then, as your intuition told you, you would have leaked the memory of whatever string object was already pointed to by str.
As pointed earlier, when you add a variable to a class in C++, you must think of whether the variable is owned by the object, or by something else.
If it is owned by the object, than you're probably better off with storing it as a value, and copying stuff around (but then you need to make sure that copies don't happen in your back).
It is is not owned, then you can store it as a pointer, and you don't necessarily need to copy things all the time.
Other people will explain this better than me, because I am not really confortable with it.
What I end up doing a lot is writing code like this :
class Foo {
private :
Bar & dep_bar_;
Baz & dep_baz_;
Bing * p_bing_;
public:
Foo(Bar & dep_bar, Baz & dep_baz) : dep_bar_(dep_bar), dep_baz_(dep_baz) {
p_bing = new Bing(...);
}
~Foo() {
delete p_bing;
}
That is, if an object depends on something in the 'Java' / 'Ioc' sense (the objects exists elsewhere, you're not creating it, and you only wants to call method on it), I would store the dependency as a reference, using dep_xxxx.
If I create the object, I would use a pointer, with a p_ prefix.
This is just to make the code more "immediate". Not sure it helps.
Just my 2c.
Good luck with the memory mgt, you're right that it is the tricky part comming from Java ; don't write code until you're confortable, or you're going to spend hours chasing segaults.
Hoping this helps !
The general rule in C++ is that for every object created with "new" there must be a "delete". Making sure that always happens in the hard part ;) Modern C++ programmers avoid creating memory on the heap (i.e. with "new") like the plague and use stack objects instead. Really consider whether you need to be using "new" in your code. It's rarely needed.
If you're coming from a background with garbage collected languages and find yourself really needing to use heap memory, I suggest using the boost shared pointers. You use them like this:
#include <boost/shared_ptr.hpp>
...
boost::shared_ptr<MyClass> myPointer = boost::shared_ptr<MyClass>(new MyClass());
myPointer has pretty much the same language semantics as a regular pointer, but shared_ptr uses reference counting to determine when delete the object it's referencing. It's basically do it yourself garbage collection. The docs are here: http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm
I'll just write a class for you.
class A
{
Foo * foo; // private by default
public:
A(Foo * foo_): foo(foo_) {}
A(): foo(0) {} // in case you need a no-arguments ("default") constructor
A(const A &a):foo(new Foo(a.foo)) {} // this is tricky; explanation below
A& operator=(const &A a) { foo = new Foo(a.foo); return *this; }
void setFoo(Foo * foo_) { delete foo; foo = foo_; }
~A() { delete foo; }
}
For classes that hold resources like this, the copy constructor, assignment operator, and destructor are all necessary. The tricky part of the copy constructor and assignment operator is that you need to delete each Foo precisely once. If the copy constructor initializer had said :foo(a.foo), then that particular Foo would be deleted once when the object being initialized was destroyed and once when the object being initialized from (a) was destroyed.
The class, the way I've written it, needs to be documented as taking ownership of the Foo pointer it's being passed, because Foo * f = new Foo(); A a(f); delete f; will also cause double deletion.
Another way to do that would be to use Boost's smart pointers (which were the core of the next standard's smart pointers) and have boost::shared_ptr<Foo> foo; instead of Foo * f; in the class definition. In that case, the copy constructor should be A(const A &a):foo(a.foo) {}, since the smart pointer will take care of deleting the Foo when all the copies of the shared pointer pointing at it are destroyed. (There's problems you can get into here, too, particularly if you mix shared_ptr<>s with any other form of pointer, but if you stick to shared_ptr<> throughout you should be OK.)
Note: I'm writing this without running it through a compiler. I'm aiming for accuracy and good style (such as the use of initializers in constructors). If somebody finds a problem, please comment.
Three comments:
You need a destructor as well.
~MyClass()
{
delete str;
}
You really don't need to use heap allocated memory in this case. You could do the following:
class MyClass {
private:
std::string str;
public:
MyClass (const std::string &_str) {
str= _str;
}
void ChangeString(const std::string &_str) {
str = _str;
};
You can't do the commented out version. That would be a memory leak. Java takes care of that because it has garbage collection. C++ does not have that feature.
When you reassign a pointer to a new object, do you have to call delete on the old object first to avoid a memory leak? My intuition is telling me yes, but i want a concrete answer before moving on.
Yes. If it's a raw pointer, you must delete the old object first.
There are smart pointer classes that will do this for you when you assign a new value.