|
From: | Maxime Boissonneault |
Subject: | Re: [Help-gsl] Just getting started - I have some 'newbie' questions. |
Date: | Thu, 22 Mar 2012 09:04:42 -0400 |
User-agent: | Mozilla/5.0 (Macintosh; Intel Mac OS X 10.7; rv:10.0.2) Gecko/20120216 Thunderbird/10.0.2 |
That is not quite correct. The C++ Standard guarantees that vectors are stored such that the i-th element of a vector v is stored in memory at the address (&v[0]+i) for all i's. This is the case since C++03. You are however correct that this was not the case before C++03.I suspected as much. I have seen various people recommending different ways of getting a pointer to the first element of an std::vector, but they all miss a couple things. The last I checked, the way memory is allocated and managed in an STL container is an implementation detail, so there is no guarantee that the contents of a vector are stored in contiguous memory. Unless the standard has changed since last I looked to provide such a guarantee, I wouldn't want to make such an assumption. Further, all bets are off when it comes to member functions that can change the contents of the vector. One of the frequent issues I see junior programmers having is that they forget that all iterators are invalidated when you start adding or removing elements. Alas, this guarantees some inefficinecies, especially when there is a need to use multiple libraries. For example, I have written a library that is quite efficient in use of std::vector in computing various statistics, especially moving statistics. But it depends on the capabilities of std::vector, and especially its forward and reverse iterators, for much of its efficiencies. To use both that code and gsl in the same program, I guess there's little option but to use gsl's vector view and matrix view on pointers to double arrays (and at least with those I can guarantee exception safety by having the memory those arrays use managed by a smart pointer), and bear the cost of one copy of the input data each time the analysis is required. At least, when doing this for a time series, and needing a moving window, I can avoid the cost of reallocating the memory used for the data.
A similar addition to the standard have also been done for the complex<T> type. Before C++11, the real and imaginary parts of complex<T> were not garanteed to be contiguous in memory, and I think there was no guarantee that there were no padding of some sort. C++11 guarantees that. That is, if you have :
complex<double> carray[10]; You are certain that : ((double *)carray)[2*i] => gives the real part of the i-th element ((double *)carray)[2*i+1] => gives the imaginary part of the i-th element.In practice, it is probable that all implementations of vector and complex were done this way from the start, but when the C++ standard comitee realized that these two things were not guaranteed by the standard, they fixed it (because it would break a lot of codes using legacy C or Fortran libraries if this was not the case).
Since C++03, you can therefore safely use a "vector<double> v" and pass "&v[0]" to a C function requiring a "double *", and since C++11, you can safely cast "complex<T> *" into a "double *" (which will have twice the length of the initial vector) to a C (or Fortran) function which expects arrays of T to represent arrays of complex T numbers.
Best, Maxime Boissonneault
[Prev in Thread] | Current Thread | [Next in Thread] |