|
-
January 6th, 2012, 04:01 AM
#14
Re: std::vector initialization problem
From Lindley:
If you are attempting to move 'rows' around as a single unit, the first-dimension-is-pointers approach is probably going to be more efficient.
From Paul McKenzie:
Then you point the rows within the table.
I hadn't thought of simply just sorting an array of pointers to each row, rather than the rows themselves. For the size of the table of exclusions, I don't think shuffling rows around will be too big of a performance hit in the context where it will be used, but the pointers-approach seems superior regardless.
Before I saw the latest advice from you all, I revisited the workaround structure idea and was able to get it working with something like the following, which I post here for interest's sake and to demonstrate the inconsistent compiler access to *this members within the lambda:
Code:
#include <vector>
#include <algorithm>
template <int N, class T> struct A {};
template <class T> struct A<1, T>
{
int static const iFirst = 0;
int static const iSecond = 1;
int static const nUnits = 2;
typedef typename std::vector<int>::size_type size_type;
size_type MyRoutine(int const nFields, size_type const (* const pFields)[nUnits]);
};
template <class T>
typename A<1, T>::size_type A<1, T>::MyRoutine(int const nFields, size_type const (* const pFields)[nUnits])
{
struct LWorkaround
{
LWorkaround(void) {}
// I've included { copy, move } X { constructors, assignment operators }
// in case the size_type template argument is ever something non-trivial.
size_type const & operator [] (size_t i) const { return m_i[i]; }
size_type m_i[nUnits];
};
static_assert(sizeof(LWorkaround) == sizeof(size_type const [nUnits]),
"Structure size is incompatible with field exclusion row.");
static_assert(sizeof(LWorkaround[100]) == sizeof(size_type const [100][nUnits]),
"Structure packing is incompatible with array packing.");
// Now I get to use vector again for the RAII effect (rather than writing a manual RAII class).
std::vector<LWorkaround> aFields;
aFields.resize(nFields);
// This is safe because the ISO standard requires vector to be compatible with
// a raw array.
LWorkaround * const pLocalFields = &aFields[0];
memcpy(pLocalFields, pFields, sizeof(pFields[0]) * nFields);
std::sort(pLocalFields, pLocalFields + nFields,
[](LWorkaround const & r1, LWorkaround const & r2)->bool
{
// Odd, if uncommented, the following declaration compiles just fine...
// size_type test[nUnits];
// ... but in contrast, if uncommented, the following declaration does not.
// size_type const (* const pFields)[nUnits] = NULL;
// Also the uses of the static members of A work here...
bool const b = r1[iFirst] == r2[iSecond];
return true;
});
return 0;
}
void main(void)
{
A<1, int> a;
a.MyRoutine(0, NULL);
}
From superbonzo:
...I'm quite sure that the lambda cannot see *this static members, unless "this" is included in the lambda capture clause ( or if those members are captured explicitly, of course ).
I guess the issue is obsolete, but I'm getting the inconsistent compiler behavior described by the comments in the lambda body. It's as if the compiler is aware of them in some instances but not others. Perhaps by the C++ standard it wouldn't have access to them at all (as superbonzo states) but the compiler implementation sometimes does have that access in a non-standard way? (That is, perhaps the code wouldn't be portable?)
Anyway, if I hybridize my preferred way of allocating the array with the great suggestion you all have made to sort an array of pointers, I end up with:
Code:
template <class T>
typename A<1, T>::size_type A<1, T>::MyRoutine(int const nFields, size_type const (* const pFields)[nUnits])
{
int i;
std::vector<size_type const (*)[nUnits]> aFields;
aFields.resize(nFields);
size_type const (** const pLocalFields)[nUnits] = &aFields[0];
for (i = 0; i < nFields; ++i)
{
pLocalFields[i] = &pFields[i];
}
std::sort(pLocalFields, pLocalFields + nFields,
[](size_type const (* & r1)[nUnits], size_type const (* & r2)[nUnits])->bool
{
bool const b = (*r1)[iFirst] == (*r2)[iSecond];
return true;
});
return 0;
}
Unfortunately, that causes the STL to have an ambiguous template specialization in the vector declaration and in the sort function. I might dig into it a little more tomorrow, but I'm about ready to settle for the workaround structure, perhaps even exposing it to the caller so the caller would pass in an array of these structures. I'm relunctant to do that because the contents of the structure are just indices with no intrinsic meaning apart from this function, and I don't want to pollute the caller's scope with excess baggage.
Regarding the atypical new [] and pointer syntax, new T[X][Y1][Y2][...][Yn] works as long as Y1 to Yn are all known at compile time. So for a horrific example, this
Code:
int nElements = 100;
int volatile (* const pThing)[4][8][2][24][43][72] = new int [nElements][4][8][2][24][43][72];
is a perfectly legitimate pointer, compiling just fine and useable in code as expected because the compiler knows both how much memory needs to be allocated for each "element" and how to compute the address of each volatile int by the (constant) size of the array dimensions. Also, it helps to remember that pointer declarations are most easily understood if you read them backwards and group by parenthesis, so in this case it would be read "pThing is a const pointer to an array of 4 by 8 by 2 by 24 by 43 by 72 volatile ints".
Thanks all!
Posting Permissions
- You may not post new threads
- You may not post replies
- You may not post attachments
- You may not edit your posts
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|