|
From: Sebastian Karlsson on 9 Apr 2008 04:43 Hi, I need to create copy constructors for a lot of my types in order to fix the common pointer problems of shallow copying. I've never thought much about it before but I've checked out the most common tutorials and they seem to suggest what I've used in the past, namely: class X { public: X( const X& a_Other ) { member = a_Other.member; } Y member; }; The problem here is that first Ys default constructor is invoked and then assignment. Using the default generated one only Ys copy constructor is invoked. Considering how the code looks this is of course pretty obvious. So I tried to use an initialization list in the copy constructor instead, which gave me the same behaviour as the default copy constructor. I can't recall seeing this used elsewhere though which kind of boggles me. The real question though is: Is it possible to first create a shallow copy using the default copy constructor and then afterwards clean up the pointer problems etc. I would stay have to pay for some unecessary pointer copying, but it would save me from maintaining huge initilization lists for types which mostly have default copyable members. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Ulrich Eckhardt on 9 Apr 2008 08:56 Sebastian Karlsson wrote: > Hi, I need to create copy constructors for a lot of my types in order > to fix the common pointer problems of shallow copying. Not only that, but the same problem also makes a user-defined assignment operator mandatory. Do a websearch for the so-called "law of three". > I've never thought much about it before but I've checked out the most > common tutorials and they seem to suggest what I've used in the past, > namely: > > class X > { > public: > X( const X& a_Other ) { member = a_Other.member; } > Y member; > }; ....which is what only a bad tutorial would suggest. Good C++ code would use initialisation instead of assignment. > The problem here is that first Ys default constructor is invoked and > then assignment. Using the default generated one only Ys copy > constructor is invoked. Considering how the code looks this is of > course pretty obvious. So I tried to use an initialization list in the > copy constructor instead, which gave me the same behaviour as the > default copy constructor. The default copy-constructor just does memberwise copy-construction, so it's the same as using an initialiser list manually. > I can't recall seeing this used elsewhere though which kind of boggles me. You haven't seen an initialiser list anywhere? In that case I'd say that your learning material isn't worth that name. Check out the book reviews at ACCU's. > The real question though is: Is it possible to first create a shallow > copy using the default copy constructor and then afterwards clean up > the pointer problems etc. What you can do is use shallow-copy initialisation and then manually clone pointees and assign to the members, but what's the point? Also, this is tough to get correct in the presence of exceptions. > I would stay have to pay for some unecessary pointer copying, but it > would save me from maintaining huge initilization lists for types which > mostly have default copyable members. Sorry, but that approach won't get you far. Copying a pointer is _WAY_ cheaper than allocating a piece of memory, so why even worry about pointers? Also, you are trying to micro-optimise things when you don't even have them working correctly yet. Lastly, some more things I'd like to mention: 1. If possible, avoid dynamic allocation. Just use plain containment instead. 2. Instead of implementing copying and assignment, you can also simply forbid their use by declaring the copy constructor and assignment operator but making them private and not implementing them. 3. If you use e.g. std::string instead of maintaining a char* to hold some text, you get automatic copying and assignment for free. Internally, they use pointers of course, but that isn't visible and that isn't something you have to worry about. Uli -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Sebastian Karlsson on 10 Apr 2008 10:40 > You haven't seen an initialiser list anywhere? In that case I'd say that > your learning material isn't worth that name. Check out the book reviews at > ACCU's. I do know about initialization lists, just not with a copy constructor. > Sorry, but that approach won't get you far. Copying a pointer is _WAY_ > cheaper than allocating a piece of memory, so why even worry about > pointers? Also, you are trying to micro-optimise things when you don't even > have them working correctly yet. > I just saw there was a typo in there which might have changed the message. I was trying to say that I don't mind the copying of the pointer, because as you said, it's cheap. I just don't want to maintain a very long initialization list if I don't have to. I'd also like to say that I do have things working correctly, it's just that I'm trying to see if there's a way to avoid a long initialization list for all my members which aren't pointers, for which I just want the compiler generated default copy constructor behavior. Sorry for the confusion. -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
From: Ulrich Eckhardt on 11 Apr 2008 02:33 Sebastian Karlsson wrote: >> You haven't seen an initialiser list anywhere? In that case I'd say that >> your learning material isn't worth that name. Check out the book reviews >> at ACCU's. > > I do know about initialization lists, just not with a copy > constructor. > >> Sorry, but that approach won't get you far. Copying a pointer is _WAY_ >> cheaper than allocating a piece of memory, so why even worry about >> pointers? Also, you are trying to micro-optimise things when you don't >> even have them working correctly yet. >> > > > I just saw there was a typo in there which might have changed the > message. I was trying to say that I don't mind the copying of the > pointer, because as you said, it's cheap. I just don't want to > maintain a very long initialization list if I don't have to. > > > I'd also like to say that I do have things working correctly, it's > just that I'm trying to see if there's a way to avoid a long > initialization list for all my members which aren't pointers, for > which I just want the compiler generated default copy constructor > behavior. Ah, I get you now. ;) In order to get the compiler-generated cctor, you must not redefine it yourself. However, there are a few tricks. 1. Move all members which you want the default to take effect to a structure. This class: class foo { int data_1; ... float data_n; bar* ptr; }; ....becomes this: class foo { struct { int data_1; ... float data_n; } data; bar* ptr; }; ....and the cctor only looks like this then: foo::foo( foo const& rhs): data(rhs.data), ptr(0) { /// deep copy rhs.ptr } 2. A different way is to not use pointers but a wrapper: struct ptr_wrapper { // copying, assignment, destructor private: bar* ptr; }; This then replaces the member 'ptr' from class 'foo' above, which can then use the default copy-constructor. Note that in general, I would advise use of #2, because it makes things more self-contained. Also note that if this wrapper's behaviour is specific to class foo, you can also nest the wrapper inside that class to make this explicit. However, #1 can come handy, too, because sometimes you have special constructors in a class (like e.g. std::string's) but otherwise still want easy implementations for copy-construction, assignment and swapping, where it's a popular mistake to forget one or two members. Uli -- [ See http://www.gotw.ca/resources/clcm.htm for info about ] [ comp.lang.c++.moderated. First time posters: Do this! ]
|
Pages: 1 Prev: templated virtual functions?? Next: std::complex and extensible literals. |