|
-
May 2nd, 2003, 10:08 AM
#1
Generic C++ object/structure swap
I developed a simple object swap template. I simply do a binary swap of the class/structure contents. Yet I know that the developers of the STL libraries do not implement swaps in this way. Their implementation will make copies (via a copy constructor) and then use an assignment operator - "operator=()". The reason I want to do swaps in this manner is because of the obvious efficiencies. For instance, if I wanted to swap two branches of two very large tree structures, the copy and assignment operations become prohibative.
My question is in what instances does the code below NOT work?
template <typename _Ty>
void ObjectSwap(_Ty &obj1, _Ty &obj2)
{
// Don't swap on the same object
if (&obj1 != &obj2)
{
char tmp[sizeof(_Ty)]; // create a memory buffer
size_t sz = sizeof(_Ty);
memcpy((void *) tmp, (const void *) &obj1, sz);
memcpy((void *) &obj1, (const void *) &obj2, sz);
memcpy((void *) &obj2, (const void *) tmp, sz);
}
}
Scott K
-
May 2nd, 2003, 10:45 AM
#2
I think your swap is guarenteed to work for POD only.
(However, I don't know of any example where it
will not work).
The following link has some info on memcpy and C++ objects:
http://www.cuj.com/experts/1912/alex...?topic=experts
-
May 2nd, 2003, 11:41 AM
#3
This would probably never be implemented, but if your object contained a pointer to one of it own member variables then it would end up poining to the wrong place.
e.g. maybe if you class iterated through a string moving the pointer to the next char each time it is called
class A
{
char String[100];
char* Ptr;
public:
A() {//some initialization}
char NextChar()
{
char ch = m_Ptr;
if(++Ptr > String + 100)
Ptr = String;
return char;
};
};
Not sureth is is true, Just a suggestion. but I imagine that the Ptr member would point to the wrong classes string after the swap
-
May 2nd, 2003, 11:48 AM
#4
Re: Generic C++ object/structure swap
Originally posted by scottk@intellig
I developed a simple object swap template. I simply do a binary swap of the class/structure contents. Yet I know that the developers of the STL libraries do not implement swaps in this way. Their implementation will make copies (via a copy constructor) and then use an assignment operator - "operator=()". The reason I want to do swaps in this manner is because of the obvious efficiencies.
This is not guranteed to work for non-POD types.
What is a POD type? A POD type is a basic data type (int, char, double, float, etc.), a structure or class that contains these types, or arrays of these types -- basically anything that 'C' can handle as far as data types go. If you are swapping a class or struct that contains member functions, destructors, or contain members that are not POD themselves, your swap will cause undefined behavior and your program to be unstable.
Your method will work if you can guarantee that the types you are swapping are POD (Plain Old Data) types. Then you can do a specialization for std::swap (which is the proper way to do what you want -- you don't have to write another completely different function). This allows the STL framework to call your "swap" instead of the default.
There is a reason why the default std::swap does what you observe. The reason is that to copy any object correctly and without invoking undefined behavior, you must call the objects assignment or copy constructor.
Regards,
Paul McKenzie
-
May 3rd, 2003, 07:44 AM
#5
[q]This would probably never be implemented, but if your object contained a pointer to one of it own member variables then it would end up poining to the wrong place.[/q]
There is another, more common situation in which the problem could occur. If your object contains a pointer to memory allocated on the heap and its destructor deallocates the memory (which it should), you'll have a problem.
Say you have one instance of your object A, and you bitwise copy it to another instance B. If, say, B is destructed because it goes out of scope, it will deallocate the block of memory that its pointer points to. Since the copy was just a bit-by-bit copy, A's pointer still points to that same block, which has now been deleted. Not a good thing.
-
May 3rd, 2003, 05:45 PM
#6
This is true of making copies of classes containing dynamicaly allocated data. However as you end up trying to dlete memory twice or use memory after one instance has already deleted it.
In this case though the objects are bing SWAPPED so the allocated memory stays in the same place and the pointers two it aree swapped. Both pointer both only exist in one instance after the swap and the problem doesn't occur
-
May 4th, 2003, 01:29 PM
#7
I am coming to the conclusion that there are some rules that would need to be adhered to in order for an object swap to be workable.
Rule #1: All pointers within the object that reference allocated memory must be private and completely managed by the object or set of objects.
Rule #2: All data in an object must be contained within a POD structure.
Rule #3: The object can not contain any pointers to itself.
In view of the above rules, I would rewrite the object swap code as follows:
// Note: all objects must have all their data in a structure called 'pod'.
template <typename _Ty>
void ObjectSwap(_Ty &obj1, _Ty &obj2)
{
// Don't swap on the same object
if (&obj1 != &obj2)
{
char tmp[sizeof(_Ty.pod)]; // create a memory buffer
size_t sz = sizeof(_Ty.pod);
memcpy((void *) tmp, (const void *) &obj1.pod, sz);
memcpy((void *) &obj1.pod, (const void *) &obj2.pod sz);
memcpy((void *) &obj2.pod, (const void *) tmp, sz);
}
}
class Obj
{
private:
struct
{
int number;
char *name
} pod;
public:
Obj() : pod.number(0), pod.name(new char[10] {}
~Obj() { delete pod.name; }
swap(Obj &rhs)
{
ObjectSwap<Obj>(rhs);
}
};
Does this then follow all the edicts of C++?
Last edited by scottk@intellig; May 4th, 2003 at 01:32 PM.
Scott K
-
May 4th, 2003, 03:21 PM
#8
Your Obj class has no copy constructor or assignment operator. This is slightly off-topic, but your class will fail this simple test:
Code:
int main()
{
Obj a;
Obj b = a;
Obj c;
c = a;
} // Crash?
The reasons why your Obj object will more than likely crash this code is that a, b, and c will be deleting the same pointer on destruction. If you code a destructor, you should also code an assignment and copy constructor.
Regards,
Paul McKenzie
-
May 4th, 2003, 04:09 PM
#9
true. That was an oversite on my part. I was mainly focusing in the swap operation.
What did you think of the idea of putting all class data inside a POD (Plain Old Data) structure to avoid the C++ issues of moving objects?
As I have discovered, it is an invalid operation in C++ to move a classes location without using the copy constructor and/or assignment operators if it is NOT a POD class/struct, and it can not be a POD class/struct if any constructor/destrctor methods are defined, or there are any virtual methods.
Scott K
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|