Proper way to reassign pointers in C ++

EDIT: I know, in this case, if it were an actual class, I would be better off not putting a string in a heap. However, this is just a sample code so that I understand the theory. The actual code will be a red ebony with all nodes stored on the heap.

I want to make sure that I have these basic ideas right before moving on (I come from the Java / Python background). I searched the network, but have not yet found a specific answer to this question.

When you reassign a pointer to a new object, do you need to call delete on the old object first to avoid memory leak? My intuition tells me that yes, but I want to get a specific answer before moving on.

For example, suppose you have a class that stores 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 will this be correct?

I think they hang me up if you don't use the new keyword for the second path, it will still compile and run as you expected. Does it just overwrite the data that this pointer points to? Or is he doing something else?

Any advice would be very helpful: D

+6
c ++ memory-management pointers
source share
7 answers

If you must free the old instance and create another, first make sure that the creation of the new object is complete:

 void reset(const std::string& str) { std::string* tmp = new std::string(str); delete m_str; m_str = tmp; } 

If you first call delete and then create a new one, throw an exception, then the class instance will be left with a dangling pointer. For example, your destructor may try to delete the pointer again (undefined behavior).

You could also avoid this by setting the pointer to NULL between them, but the above method is even better: if the reset fails, the object will retain its original value.


Regarding the question in the code comment.

 *str = _str; 

That will be the right thing. This is the normal assignment of strings.

 str = &_str; 

This will be the assignment of pointers and completely wrong. You would skip the string instance that str previously pointed to. Worse, it is likely that the line passed to the function is not primarily allocated by new (you should not mix pointers with dynamically allocated and automatic objects). In addition, you can store the address of a string object whose lifetime ends with a function call (if the reference to the constant is tied to a temporary one).

+12
source share

Why do you think you need to keep a pointer to a string in your class? Pointers to C ++ collections, such as strings, are actually very rarely needed. Your class should almost certainly look like this:

 class MyClass { private: std::string str; public: MyClass (const std::string & astr) : str( astr ) { } void ChangeString(const std::string & astr) { str = astr; } .... }; 
+3
source share

Just highlight here, but

 str = _str; 

will not compile (you are trying to assign _str, which is the value of the string passed by reference, to str, which is the address of the string). If you want to do this, write:

 str = &_str; 

(and you will need to change either _str or str so that constnest matches).

But then, as your intuition told you, you would have leaked into the memory of which string object the string is already pointed to.

As stated earlier, when you add a variable to a C ++ class, you should think about whether this variable belongs to an object or something else.

If it belongs to an object, you will most likely be better off storing it as a value and copying the contents (but then you need to make sure that the copies are not running in your back).

It does not belong, then you can save it as a pointer, and you do not have to copy all the time.

Other people will explain it better than me, because I really can't handle it. What I end up doing a lot is writing code as follows:

 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 sense of "Java" / "Ioc" (objects exist elsewhere, you do not create it, and you only want to call the method on it), I would save the dependency as a reference, using dep_xxxx.

If I create an object, I would use a pointer with the p_ prefix.

This is just to make the code more β€œimmediate”. Not sure if this helps.

Just my 2c.

Good luck with mgt's memory, you're right that this is the hard part coming from Java; do not write code until you are comfortable, or you will spend hours chasing segaults.

Hope this helps!

+1
source share

The general rule in C ++ is that for every object created using the "new", there must be a "delete". Make sure that this always happens in the difficult part;) Modern C ++ programmers do not create memory on the heap (i.e., C "new") like the plague, and instead use stack objects. Think about whether you need to use the β€œnew” in your code. This is rarely needed.

If you come from a background with garbage-collected languages ​​and find that you really need to use heap memory, I suggest using general boost pointers. You use them as follows:

 #include <boost/shared_ptr.hpp> ... boost::shared_ptr<MyClass> myPointer = boost::shared_ptr<MyClass>(new MyClass()); 

myPointer has almost the same language semantics as a regular pointer, but shared_ptr uses reference counting to determine when the object it refers to is deleted. This is mainly done by the garbage collector. Documents are here: http://www.boost.org/doc/libs/1_42_0/libs/smart_ptr/smart_ptr.htm

+1
source share

I'll just write you a class.

 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 store such resources, you need a copy constructor, an assignment operator, and a destructor. The hard part of the copy constructor and assignment operator is that you need to remove each Foo exactly once. If the copy constructor initializer said :foo(a.foo) , then the specific Foo would be deleted once when the initialized object was destroyed and once when the object initialized from ( a ) was destroyed.

The class, as I wrote it, must be documented as having a Foo pass, which is passed because Foo * f = new Foo(); A a(f); delete f; Foo * f = new Foo(); A a(f); delete f; will also result in double deletion.

Another way to do this is to use Boost smart pointers (which were the core of the following standard smart pointers) and boost::shared_ptr<Foo> foo; instead of Foo * f; in the class definition. In this case, the copy constructor should be A(const A &a):foo(a.foo) {} , since the smart pointer will take care of deleting Foo when all copies of the shared pointer pointing to it are destroyed. (There you can get problems here, especially if you mix shared_ptr<> with any other form of pointer, but if you stick to shared_ptr<> everything should be fine.)

Note. I am writing this without running it through the compiler. I am aiming for precision and good style (e.g. using initializers in constructors). If someone finds a problem, please comment.

+1
source share

Three comments:

You also need a destructor.

 ~MyClass() { delete str; } 

In this case, you do not need to use the allocated heap memory. You can 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 cannot execute the commented version. This will be a memory leak. Java takes care of this because it has garbage collection. C ++ does not have this feature.

0
source share

When you reassign a pointer to a new object, do you need to call delete on the old object first to avoid memory leak? My intuition tells me that yes, but I want to get a specific answer before moving on.

Yes. If this is a raw pointer, you must first delete the old object.

There are classes of smart pointers that will do this for you when you assign a new value.

0
source share

All Articles