FAQ 25.05 Should a template use memcpy() to copy objects of its template argument?No. An object should be bitwise copied only when it is known that the class of the object will forever be amenable to bitwise copy. But the class of a template argument can't be known. Here is an example. #include <cstring> #include <new> using namespace std; template<class T> class Array { public: Array(unsigned len=10); Array(const Array<T>& a); // copy constructor Array<T>& operator= (const Array<T>& a); // assignment ~Array() throw(); unsigned len() const throw(); const T& operator[] (unsigned i) const throw(); T& operator[] (unsigned i) throw(); protected: unsigned len_; T* arr_; }; template<class T> inline Array<T>::Array(unsigned len) : len_(len), arr_(new T[len]) { } template<class T> inline Array<T>::~Array() throw() { delete[] arr_; } template<class T> inline unsigned Array<T>::len() const throw() { return len_; } template<class T> inline const T& Array<T>::operator[] (unsigned i) const throw() { return arr_[i]; } template<class T> inline T& Array<T>::operator[] (unsigned i) throw() { return arr_[i]; } template<class T> Array<T>::Array(const Array<T>& a) : len_(a.len_) , arr_(new T[a.len_]) { #if 1 for (unsigned i = 0; i < len_; ++i) <-- 1 arr_[i] = a.arr_[i]; #else memcpy(arr_, a.arr_, len_*sizeof(T)); <-- 2 #endif } template<class T> Array<T>& Array<T>::operator= (const Array<T>& a) { if (len_ != a.len_) { <-- 3 T* arr2 = new T[a.len_]; delete[] arr_; arr_ = arr2; len_ = a.len_; } #if 1 // GOOD FORM: lets the T objects copy themselves for (unsigned i = 0; i < len_; ++i) <-- 4 arr_[i] = a.arr_[i]; #else // BAD FORM: manipulates the bits of the T objects memcpy(arr_, a.arr_, len_*sizeof(T)); <-- 5 #endif return *this; }
If a template uses memcpy() to copy some T objects, the template must have a big, fat, juicy comment warning potential users that a class with nontrivial copy semantics might destroy the world. For example, if memcpy() were used in the example class template, and if someone created an Array<string>, it is likely that the memcpy() would create dangling references and/or wild pointers, and they would probably crash the application (see FAQ 32.01). Finally, notice that the member functions that create T objects (that is, the constructors and the assignment operator) do not have exception specifications (see FAQ 9.04). This is because the T object's constructor may throw arbitrary exceptions, and any restrictions placed on these template member functions would be wrong for some particular type T. |