The pin_ptr would be needed if you were going to pass the pin_ptr directly to an unmanaged API as a double*
.
void SomeUnmanagedAPI(double* data, int length);
// Example of where pin_ptr would be needed.
pin_ptr<double> pinnedValues = &managedValues[0];
SomeUnmanagedAPI(pinnedValues, managedValues->Length);
For either the manual copy, or the Marshal::Copy, it's not needed. Go ahead and remove it, and just iterate over managedValues.