Ещё о быстром move.
От: Шахтер Интернет  
Дата: 09.10.04 20:20
Оценка:
Я тут набросал пару примеров, как можно быстро двигать вектора.

Второй пример на VC++ 7.1 генерирует, по-видимому, неулучшаемый код.

; 114  :   
; 115  :   FastMoveVector(mem2,vec1,vec1+Size);

    lea    ecx, DWORD PTR _mem1$[esp+200]
    lea    edx, DWORD PTR _mem2$[esp+200]
    xor    eax, eax
    npad    8
$L14160:
    mov    esi, DWORD PTR _mem1$[esp+eax+196]
    mov    DWORD PTR _mem2$[esp+eax+196], esi
    mov    esi, DWORD PTR [ecx]
    add    eax, 8
    mov    DWORD PTR [edx], esi
    lea    esi, DWORD PTR _mem1$[esp+eax+196]
    lea    ebp, DWORD PTR _mem1$[esp+276]
    add    ecx, 8
    add    edx, 8
    cmp    esi, ebp
    jb    SHORT $L14160


-- это memcpy скорость.

Единственный момент здесь -- у меня есть неясность с одним абзацем в стандарте. 3.8 4

A program may end the lifetime of any object by reusing the storage which the object occupies or by explicitly calling the destructor for an object of a class type with a nontrivial destructor. For an object of a class type with a nontrivial destructor, the program is not required to call the destructor explicitly before the storage which the object occupies is reused or released; however, if there is no explicit call to the destructor or if a delete expression (5.3.5) is not used to release the storage, the destructor shall not be implicitly called and any program that depends on the side effects produced by the destructor has undefined behavior.

Пример 1.

/* MoveVector.cpp */ 

#include <iostream>

using namespace std;

/* Replace<T>() */ 

template <class T>
inline T Replace(T &var,T val) { T ret=var; var=val; return ret; }

/* class MoveSrc<T> */ 

template <class T>
class MoveSrc
 {
   T *src;
 
  public:
  
   MoveSrc(T &x) : src(&x) {}
   
   T * operator -> () const { return src; }
 };
 
/* class String */  

class String
 {
   char *str;
   size_t len;
   
   String(const String &) {}
   
   void operator = (const String &) {}
   
   static char * GetNull(); 
 
  public:
  
   String() : str(GetNull()),len(0) {}
   
   String(const char *str_);
   
   explicit String(MoveSrc<String> x)
    {
     str=Replace(x->str,GetNull());
     len=Replace(x->len,size_t(0));
    }
   
   ~String();
   
   const char * getStr() const { return str; }
   
   size_t getLen() const { return len; }
   
   String * moveObjectTo(void *mem)
    {
     __assume(mem);
     
     return new(mem) String(MoveSrc<String>(*this));
    }
 };

char * String::GetNull()
 {
  static char zero[1];
  
  return zero;
 }
 
String::String(const char *str_)
 {
  len=strlen(str_);
  
  str=new char[len+1];
  
  memcpy(str,str_,len+1);
  
  cout << "new char[" << len+1 << "]\n" ;
 }
   
String::~String()
 {
  if( str!=GetNull() ) 
    {
     delete[] str;
     
     cout << "delete char[]\n" ;
    }
 }
 
/* MoveVector<T>() */  

template <class T>
void MoveVector(void *mem,T *ptr,T *lim) throw()
 {
  for(; ptr<lim ;ptr++,mem=static_cast<char *>(mem)+sizeof (T)) 
    {
     ptr->moveObjectTo(mem);
     
     (*ptr).~T();
    }
 }
   
/* main() */ 

const size_t Size=10;

int main()
 {
  char mem1[Size][sizeof (String)];
  char mem2[Size][sizeof (String)];
  
  String *vec1=static_cast<String *>((void *)mem1);
  String *vec2=static_cast<String *>((void *)mem2);
  
  for(size_t i=0; i<Size ;i++) new(mem1[i]) String("string");
  
  for(size_t i=0; i<Size ;i++) cout << vec1[i].getStr() << '\n' ;
  
  MoveVector(mem2,vec1,vec1+Size);
 
  for(size_t i=0; i<Size ;i++) cout << vec2[i].getStr() << '\n' ;
  
  for(size_t i=0; i<Size ;i++) vec2[i].~String();
  
  return 0;
 }


Пример 2.

/* FastMoveVector.cpp */ 

#include <iostream>

using namespace std;

/* class FastMoveSrc<T> */ 

template <class T>
class FastMoveSrc
 {
   T *src;
 
  public:
  
   FastMoveSrc(T &x) : src(&x) {}
   
   T * operator -> () const { return src; }
 };
 
/* class String */  

class String
 {
   char *str;
   size_t len;
   
   String(const String &) {}
   
   void operator = (const String &) {}
   
   static char * GetNull(); 
 
  public:
  
   String() : str(GetNull()),len(0) {}
   
   String(const char *str_);
   
   explicit String(FastMoveSrc<String> x)
    {
     str=x->str;
     len=x->len;
         
     // Исходный объект после этой операции становится невалидным и не должен больше использлваться -- включая вызов деструктора
    }
   
   ~String();
   
   const char * getStr() const { return str; }
   
   size_t getLen() const { return len; }
   
   String * fastMoveObjectTo(void *mem)
    {
     __assume(mem);
     
     return new(mem) String(FastMoveSrc<String>(*this));
    }
 };

char * String::GetNull()
 {
  static char zero[1];
  
  return zero;
 }
 
String::String(const char *str_)
 {
  len=strlen(str_);
  
  str=new char[len+1];
  
  memcpy(str,str_,len+1);
  
  cout << "new char[" << len+1 << "]\n" ;
 }
   
String::~String()
 {
  if( str!=GetNull() ) 
    {
     delete[] str;
     
     cout << "delete char[]\n" ;
    }
 }
 
/* FastMoveVector<T>() */  

template <class T>
void FastMoveVector(void *mem,T *ptr,T *lim) throw()
 {
  for(; ptr<lim ;ptr++,mem=static_cast<char *>(mem)+sizeof (T)) 
    {
     ptr->fastMoveObjectTo(mem);
        
     // Считаем объект убитым и не вызываем деструктор.
    }
 }
   
/* main() */ 

const size_t Size=10;

int main()
 {
  char mem1[Size][sizeof (String)];
  char mem2[Size][sizeof (String)];
  
  String *vec1=static_cast<String *>((void *)mem1);
  String *vec2=static_cast<String *>((void *)mem2);
  
  for(size_t i=0; i<Size ;i++) new(mem1[i]) String("string");
  
  for(size_t i=0; i<Size ;i++) cout << vec1[i].getStr() << '\n' ;
  
  FastMoveVector(mem2,vec1,vec1+Size);
 
  for(size_t i=0; i<Size ;i++) cout << vec2[i].getStr() << '\n' ;
  
  for(size_t i=0; i<Size ;i++) vec2[i].~String();
  
  return 0;
 }
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.