----------------------------------------------
> I have someone on another forum who has made the following claim about
> objects and usage of memcpy(), more importantly, usage of qsort() on
> objects.
> Here is the claim:
> ------------ CUT HERE -------------------------
> In doing object sorting, no object creation or destruction should be
> involved. We are just moving objects around from one memory location to
> another location.
>
> It is highly likely that by merely shifting an object in the memory
> would not change the property of the object. The object should look just
> the same before and after the shift. In such case it is perfectly OK to
> just memcpy to swap objects or move them to a different location.
>
Wrong.
Standard says:
"For any object (other than a base-class subobject) of POD
type T, whether or not the object holds a valid value of type T,
the underlying bytes (1.7) making up the object can be copied
into an array of char or unsigned char.
If the content of the array of char or unsigned char is copied
back into the object, the object shall subsequently hold its
original value." (3.9/2)
There are defect reports on this wording, particulary regarding
PODs with non-static "const" members (proposed resolution is to
remove the above guarantee from such PODs), but the intent
remains the same:
Standard does not give such guarantees for non-POD types.
Furthermore, Standard says:
"An object of POD type shall occupy contiguous bytes
of storage" (1.8/5)
There is no such guarantee for non-POD types.
And the last (but not the least): Standard says:
"A pointer to a POD-struct objects, suitably converted using
a reinterpret_cast, points to its initial member (or if that member is
a bit-field, then to the unit in which it resides) and vice versa.
[Note: there might therefore be unnamed padding within a POD-struct
object, but not at its beginning, as necessary to achieve appropriate
allignment.]" (9.2/17)
There is no such requirement for non-PODs.
> If in the rare case, the object's property DO depend on its memory
> location. Then such objects can not be copied, and no proper copy
> constructor can be written.
Wrong.
Consider so-called "base-pointers", like this one
(everything is snipped, but I hope that idea is clear):
// _not_ intended to compile, just a sketch
ptrdiff_t pointer_to_offset(const void* base, const void* p);
template<typename T>
T* offset_to_pointer(const void* base, ptrdiff_t offset);
template<typename T>
struct based_ptr
{
based_ptr( T* p_ )
: p( pointer_to_offset(this, p_) {}
based_ptr( const based_ptr& p_ )
: p( pointer_to_offset(this, (T*)p_ ) {}
based_ptr& operator= ( const based_ptr& p_ )
{ p= pointer_to_offset(this, (T*)p_ ); return *this; }
based_ptr& operator= ( T* p_ )
{ p= pointer_to_offset(this, p_ ); return *this; }
operator T* () const
{ return offset_to_pointer<T>(this,p); }
T* operator -> () const
{ return offset_to_pointer<T>(this,p); }
T& operator -> () const
{ return *offset_to_pointer<T>(this,p); }
private:
ptrdiff_t p;
};
Such "pointers" are helpful when doing some low-level tricks,
and they can be easily made "Assignable", "Comparable" etc.
Note that they _do_ have proper and correct copy constructor's
and assignment operator's semantics.
If you implement based pointers (or any other such classes)
properly, you can use them in containers, perform
std::sort or any other algorithms etc etc
(Indeed, offset_to_pointer<T> and pointer_to_offset cannot
be written portably, they are implementation/platform-specific
operations, and there might be platforms where these operations
is impossible to implement. But this is other issue.)
> Because you would have to copy the object
> into exactly the same memory location to make it look and behave exactly
> the same!!!
>
Nonsense.
> In such rare cases, qsort() would not work properly, but neither
> std::sort() would work.
Wrong.
std::sort() will work correctly with containers of the above pointers,
while qsort() will indeed corrupt everything.
> Since std::sort() requires an appropriate copy
> constructor, but I already said no proper copy constructor can be
> written since once the object is copied to a different location, it no
> longer behave the same even every thing else is the same!!!
Wrong.
> --------------- CUT HERE --------------------------------------
>
> Excusing the typos, can anyone here comment on the above? This all
> started with an argument over whether qsort() is safe to use on all
> objects, as opposed to always using std::sort().
>
qsort() is unsafe, it knows nothing of C++ objects, and it can be used
only with PODs without non-static const members.
memcpy() is unsafe, it knows nothing of C++ objects, and it can be used
only with PODs without non-static const members.
std::sort() is safe to use, as long as all C++ standard library requirements
are met.
Hope it make things clearer,
Sincerely,
Ruslan Abdikeev
Brainbench MVP for Visual C++
http://www.brainbench.com
------------------------------------------------------------------------