Classes with pointer elements and no overridden copy constructor

When pointers point to something declared in the same class, am I right in thinking that if you copy such an object that there are several sets of pointers, but they all point to the same object (s)?

Does this mean that there are other objects in other instances of the class that were created, but that nothing points to?

And as a side question, can I be right in thinking that a common pointer will indicate all classes in ONE set of objects, but in a safe way?

+6
source share
4 answers

yes - when you do not define a copy constructor, the compiler will give you one - which will make a shallow copy - just copy the values ​​(i.e. address) of the pointers.

Thus, two objects (the original and the β€œcopy”) will have pointer fields pointing to the same object.

+3
source

If you do not deep copy the object, that is, if you do not override the c'tor copy and make a shallow copy, the pointer (s) will point to the same instance of the object. If you then delete one of the objects with a shallow copy, then the pointers of the other objects will point to garbage. If you play them in any way, your program will fail.

The same thing can happen with the assignment operator. Therefore, when you have pointers, they overload them both.

Example:

struct Message { Message(const LogType_E & type_in = LOG_ERROR, const unsigned int & domain_in = 0, const int & msgId_in = 0, const char * msg_in = ""); int myMsgID; //!< message id unsigned int myDomain; //!< message domain LogType_E myType; //!< message type char * myMsg; //!< actual message ~Message() { if(myMsg != NULL) delete [] myMsg; } Message(const Message &); const Message& operator=(const Message & rhs); }; 

This is the type of message used to store messages with other items.

The implementation will look like this:

 Message::Message(const Message & cp_in):myType(cp_in.myType), myDomain(cp_in.myDomain), myMsgID(cp_in.myMsgID), myMsg(NULL) { if(cp_in.myMsg != NULL) { myMsg = new char[strlen(cp_in.myMsg)+1]; memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1); } } const Message & Message::operator =(const AX::Base::Log::Message &cp_in) { if (this == &cp_in) // protect against invalid self-assignment return *this; //deallocate old memory if(myMsg != NULL) delete [] myMsg; if(cp_in.myMsg != NULL) { //allocate new memory and copy the elements myMsg = new char[strlen(cp_in.myMsg)+1]; memcpy (myMsg, cp_in.myMsg, strlen(cp_in.myMsg)+1); } // copy other data members myType = cp_in.myType; myDomain = cp_in.myDomain; myMsgID = cp_in.myMsgID; return *this; } 

However, use std::string to avoid all these things - this was just a proof of concept example.

+2
source

Let the code talk to understand things:

 struct X { int data; int *ptr; X() : ptr(&data) {} }; X a; X b = a; // yes, `a.ptr` points to `b.data`! 

In fact, pointers will be copied verbatim and will point to the source of the copy.

Use Member Index

Fixed this way:

 struct X { int data; int X::*ptr; X() : ptr(&X::data) {} }; X a; X b = a; // now, `a.ptr` points to `a.data` 

Extending this example with a few more tips for using https://ideone.com/F0rC3

 a.ptr = &X::data2; // now `a.ptr` points to `a.data2` // `b.ptr` points to `b.data1` b = a; // `b.ptr` points to `b.data2` too // Usage hint: int deref = a.*(a.ptr); // gets the field pointed to by a.ptr, from the instance a deref = b.*(b.ptr); // gets the field pointed to by b.ptr, from the instance b // but of course you could get fancy and do deref = a.*(b.ptr); // gets the field pointed to by b.ptr, **but** from the instance a 

This will do what you probably want. Although, why do you want it to be higher than me (and outside of C ++, maybe)

+1
source

Imagine you have a class similar to the one that shows the problem you asked in the question

 class Foo{}; class Bar { public: Foo* mFoo; Bar() : mFoo( new Foo() ) {} ~Bar() { delete mFoo;} }; 

And code like this

 Bar x ; Bar y = x; 

The above code will cause a core dump, since both y and x will point to the same Foo , and the destructor will try to delete the same Foo twice.

ALTERNATIVE 1

Declare but not provide a definition so that Bar never creates a constructor or assigns it. Will guarantees that Bar y = x will have a communication error, since you created a class that will not be copied.

 class Bar { public: Foo* mFoo; Bar() : mFoo( new Foo() ) {} ~Bar() { delete mFoo;} Bar(const Bar &); Bar& operator= (const Bar &); }; 

ALTERNATIVE 2

Provide a copy constructor and assignment operator that do the right thing. Instead of having the compiler provide a default copy and assignment implementation that make a shallow copy, you duplicate Foo so that both x and y have their own Foo

 class Bar { public: Foo* mFoo; Bar() : mFoo( new Foo() ) {} ~Bar() { delete mFoo;} Bar(const Bar & src) { mFoo = new Foo( *(src.mFoo) ); } Bar& operator= (const Bar & src) { mFoo = new Foo( *(src.mFoo) ); return *this; } }; 

ALTERNATIVE 3 (BEST)

Use C ++ 11 shared_ptr or increase and omit copy and assignment, since the default compiler provides the correct operation, since shared_ptr only counts and removes Foo once, although both x and y have the same Foo . Also note that ~Bar does not require explicit cleanup, since mFoo will be automatically deleted in the std::shared_ptr<Foo> destructor when refcount Foo becomes zero.

 class Bar { public: std::shared_ptr<Foo> mFoo; Bar() :mFoo( new Foo() ) {} ~Bar() { } }; 
+1
source

Source: https://habr.com/ru/post/903195/


All Articles