deep copies are, one has error and one is shallow copy!
Code:a=b; *x=*y;
deep copies are, one has error and one is shallow copy!
Code:a=b; *x=*y;
S_ccess is waiting for u. Go Ahead, put u there.
a = b is not a shallow copy. Remember the types of a and b!
But you did find the deep copy. So give your code, how would you make a deep copy? You can relate to the example (substitute for x and y, the pointers since your types are also pointers) if the answer isn't clear!
i meant actually
Following are the deep copies,
For the rest, One has the error and one is shallow copy.Code:a = b; *y = *x;
S_ccess is waiting for u. Go Ahead, put u there.
Hence it means, code will perform perfect deep copy.
Code:dataPtr = d.dataPtr;
O_oHence it means, code will perform perfect deep copy.
Nope.
Elysia has given some clear examples.
You are "shallow copying" by only copying a reference (pointer).
That may be what you want, but it is not a "deep copy".
Soma
Okay, there are several issues here:
(1) Anytime the requirement for a deep copy of a pointer arises, you must consider the "Rule of Three". Incidentally, having to implement all of that (and doing it correctly) over and over get's REALLY old after a while! Fortunately, the use of some sort of smart pointer object is all that is needed to relieve you from such "manual" work.
(2) Assigning the result of the "new" operator to anything other than a smart pointer is a violation of RAII and proper exception safety, and often leads DIRECTLY to the manifestation of bugs in your code. If anyone tells you different, they're just plain ignorant.
(3) You should avoid native arrays except in the most trivial cases (lookup tables and the like). They just force you back into the dark ages of programming in C, as you have to constantly consider initialization and assignment issues, and are quite often the source of buffer overflow bugs. Use something like std::string, std::array, or std::vector instead.
Yes, writing safe and robust programs in C++ does require the adherence to certain methodologies. That said, the techniques really aren't so complicated or difficult to learn, so nothing to worry about too much anyway...
Last edited by Sebastiani; 06-18-2013 at 01:22 PM.
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
O_oFortunately, the use of some sort of smart pointer object is all that is needed to relieve you from such "manual" work.
The original post actually shows a motivating counter example.
Using a normal smart pointer doesn't "deep copy" the "pointee": the expression `*objptr1 = *objptr2' shares or transfers the resource owned by the smart pointer.
Using a "cloning" smart pointer allows the expression `*objptr1 = *objptr2' to copy the "pointee", but a "cloning" smart pointer will require some form of a "clone" mechanisms which will generally be a method which will, itself, be easier to write using a copy constructor. The default form of the copy constructor could not be used because the default also copies the "cloning" pointer resulting in infinite recursion.
The point here is that relying on the default "big three" is great when you are using facilities which take care of themselves, but you have to be mindful of constructs where "taking care of themselves" still does the wrong thing.
You don't need a smart pointer to get exception safety.Assigning the result of the "new" operator to anything other than a smart pointer is a violation of[...] proper exception safety.
In point of fact, you only need to isolate problematic constructs, ones that may raise an exception, behind a point of commit or rollback semantics using operations which do not raise exceptions. This isolation is simply what smart pointers do for client code.
Now, I'm not, in any way, arguing that smart pointers should not be used. You should use smart pointers, and if at all possible, you should never manually destroy a resource.
The point here is that exception safety is born of using exception safe constructs however they may look, and using smart pointers only get you so far.
In cases like this, where the acquisition of a resource is the crucial point of failure, you don't need a resource owning "RAII" object to do the work.Code:template < typename FType > struct STest { STest(): m(new FType); // Rollback or Success { } STest ( const STest & f ): m(new FType(*f.m)) // Rollback or Success { } STest & operator = ( const STest & fOther ) { STest(fOther).swap(*this); // Rollback or Success return(*this); } ~STest() { delete m; } void swap ( STest & fOther ) // This can't raise an exception as the underlying operations don't raise an exception. { using std::swap; swap(m, fOther.m); } FType * m; };
Here I am using `char' and "C strings", but the same concepts, isolating crucial failures behind a single point of entry, apply to any type, collection, and algorithm which may be built from operations which do not raise exceptions once the critical point of failure has passed.Code:char * strdup ( const char * fString ) { char * sResult(new char[strlen(fString) + 1]); // Rollback or Success return(strcpy(sResult, fString)); // This does not raise an exception. } // ... char * DoConvert_imp ( const char * fString ) { char * sResult(strdup(fString)); // Rollback or Success // Use operations which do not raise exceptions, assigning `char' which are integers, to do case conversion. return(sResult); } // ... char * DoConvert ( const char ** fString ) { char * sResult(DoConvert_imp(*fString)); // Rollback or Success delete[] *fString; // We assume this can't raise an exception for the obvious reason. *fString = sResult; // We've only assigned a pointer which doesn't raise an exception. return(sResult); }
Actually, this is exactly how resource owning "RAII" objects are developed which are more complex than smart pointers.
Soma
Last edited by phantomotap; 06-18-2013 at 03:08 PM.
When I say "smart pointer", I'm simply refering to some sort of object to delegate the task of managing the pointer PROPERLY (however that may be). So long as the correct type of smart pointer is used (which of course may have to be coded "from scratch"), the Big Three will be taken care of.Originally Posted by phantomotap
Right, well sometimes it isn't even possible to "isolate" such things (consider passing directly new'ed objects as multiple parameters to a function, for instance). I say use a smart pointer and be done with it - eh?Originally Posted by phantomotap
Code:#include <cmath> #include <complex> bool euler_flip(bool value) { return std::pow ( std::complex<float>(std::exp(1.0)), std::complex<float>(0, 1) * std::complex<float>(std::atan(1.0) *(1 << (value + 2))) ).real() < 0; }
Perhaps it would be a good time for you to have a go now, and post your attempt.
The best way to handle a class (lets call it "foo"), which has a bunch of variables but only one of which requires special code for copying some object (lets call it "bar"), is to put that certain member into a class of its own (lets call it "moo"). "moo" contains only an instance of "bar" and handles just the copying of its "bar". Then in "foo", you can just use an instance of "moo" instead of an instance of "bar", and avoid having to implement the copy-constructor in "foo" at all. You're implementing the exact same operations on "bar", just in a different class. It simply stops you from having to specify how to copy all the other members which can already copy themselves.
You need then only realise that rather than creating your own "moo", that you've just implemented your own smart pointer, and could probably just replace "moo" with one of the standard smart pointer types, if your assignment allowed of course.
My homepage
Advice: Take only as directed - If symptoms persist, please see your debugger
Linus Torvalds: "But it clearly is the only right way. The fact that everybody else does it some other way only means that they are wrong"