Mi trovi completamente d'accordo per il punto 1, ma il punto 2 in linea teorica non si applica. I float infatti sono "arithmetic types", i quali a loro volta sono POD, e gli array di POD sono a loro volta POD (§3.9, ¶10). Per ogni tipo POD, si applica la regola descritta a §3.9, ¶3 per cui si possono copiare senza problemi con la memcpy specificando però correttamente le dimensioni del tipo; il busillis starebbe qui: se lo standard non garantisse che le dimensioni dell'array sono uguali al prodotto delle dimensioni del tipo base avremmo un problema. A §5.3.3, ¶2 si dice:
When applied to an array, the result is the total number of bytes in the array. This implies that the size of an array of n elements is n times the size of an element.
il che fa ben sperare, anche se viene da chiedersi se per "element" si possa intendere il tipo e il suo padding; d'altra parte a §8.3.4, ¶1 si dice chiaramente che
An object of array type contains a contiguously allocated non-empty set of N sub-objects of type T.
e il "contiguously allocated" dovrebbe levare ogni dubbio (cfr. invece con le struct, dove invece si parla esplicitamente del padding che potrebbe essere richiesto).

Tutto questo in teoria; se poi in giro ci siano delle implementazioni che fanno diversamente (che per questo risultano quindi automaticamente non-standard) non saprei dire.

Tra l'altro, anche se non valesse l'assunto che non c'è padding tra gli elementi, per ottenere le dimensioni in memoria dell'array (cosa che serve a memcpy) noto il suo numero di elementi, dovrebbe essere sufficiente fare:
codice:
size_t Dimensione = (size_t)(((unsigned char *)(array+NumElementi))-((unsigned char *)(array)));
dato che
  • array+NumElementi punta al (NumElementi+1)-esimo elemento sicuramente, dato che la sintassi array[i] è equivalente a *(array+i) (§8.3.4 ¶6), e, se non funzionasse quella prima sintassi, questi array sarebbero inutilizzabili ;
  • array punta al primo elemento;
  • la conversione a unsigned char * è sempre possibile per i puntatori a POD;
  • l'unità di misura della memoria (usata da sizeof) è sizeof(char)==sizeof(unsigned char), e la differenza tra i due puntatori in questione pertanto è il numero di byte che compongono l'array;
  • la (falsa) conversione da ptrdiff_t a size_t è lecita, dato che stiamo di fatto ottenendo la dimensione di un oggetto, e size_t può contenere valori di questo genere per definizione.


In ogni caso, rinnovo anch'io il consiglio ad usare std::copy; in primo luogo, è il modo idiomatico C++ per copiare degli elementi, in linea di principio meno libreria C si vede in un programma C++ meglio è.
Poi, anche se non valesse l'assunzione che non c'è padding tra gli elementi dell'array, std::copy non può fare casino, dato che, per effettuare la copia, usa puntatori al tipo corretto, quindi effettivamente copia gli elementi uno ad uno. Inoltre, std::copy funziona correttamente anche per i tipi non-POD, con i quali memcpy al 90% combina casini strani.
Poi probabilmente, se usata con POD, il compilatore dovrebbe essere sufficientemente intelligente per ottimizzarla con una chiamata a memcpy o roba analoga, per cui non si dovrebbe perdere nulla in efficienza.