CodeGuru Home VC++ / MFC / C++ .NET / C# Visual Basic VB Forums Developer.com
Results 1 to 9 of 9
  1. #1
    Join Date
    May 2003
    Location
    Minnesota
    Posts
    3

    Question 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

  2. #2
    Join Date
    Aug 2000
    Location
    West Virginia
    Posts
    7,725
    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

  3. #3
    Join Date
    Oct 2002
    Posts
    126
    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

  4. #4
    Join Date
    Apr 1999
    Posts
    27,449

    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

  5. #5
    Join Date
    Jan 2001
    Posts
    588
    [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.

  6. #6
    Join Date
    Oct 2002
    Posts
    126
    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

  7. #7
    Join Date
    May 2003
    Location
    Minnesota
    Posts
    3
    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

  8. #8
    Join Date
    Apr 1999
    Posts
    27,449
    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

  9. #9
    Join Date
    May 2003
    Location
    Minnesota
    Posts
    3
    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
  •  





Click Here to Expand Forum to Full Width

Featured