V
Vladimir Jovic
thomas said:Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Priceless! And people still pay good money for a crap called windows
thomas said:Passing vectors as arguments out of a dll in windows may crash the
system when accessing it.
Juha Nieminen said:In which system, exactly?
Unfortunately 'new' (and 'delete') is a rather heavy operation with
most C/C++ standard memory allocators, and if you use std::vector in
the place of the struct hack, you will be doing two 'news' instead of
one malloc().
If that's everything you are doing, then there's no practical difference.
However, if you are instantiating a million objects of the struct type,
then it starts making a big difference.
* tni, on 20.08.2010 10:52:
It's somewhat bad news.
C99 VLAs are, uh, monstrosities.
Usually we use the term "hack" when the code relies on a specificPete said:Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr svr[0]; //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB. How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite
a common one, too.
manifestation of undefined (or unspecified) behavior, but otherwise is
well-formed.
In this case the code is ill-formed, since 0-size array declaration is
illegal in C++ (as well as in C). In other words, arguing about the "out
of bounds" access here doesn't make much sense, since the code is
formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
Yes, but it is still easy to get DLL interface working, just pass the
data pointer always together with the pointer to the deallocation
function (wrapped into a nice C++ class of course).
One can attempt to do the same with a custom allocator for std::vector,
but this is much harder to get working as std::vector implementation is
not under user control and there is no guarantee that std::vectors of
different implementations (e.g. with _SECURE_SCL macro defined or not)
are binary compatible (they aren't).
Goran Pusic said:Why? IMO, new and delete are, on the success path, practically
equivalent on many common implementations. Difference is one if on
malloc failure, and new is inlined.
I say this claim of yours is poorly founded.
In this case, you can use vector::reserve, so not really.
And even locality of reference is not a concern, because allocators
mostly do a good job of allocating blocks close in space if allocation
is close in time. E.g.
std::vector* p = new vector;
p->reserve(X);
is in practice quite OK wrt locality.
Öö Tiib said:Ok points taken. If the "about as fast" is not fast enough and you do
not need dynamic array then use boost::array<>, it is vector with
removed overhead of dynamic size. Also it is present in technical
reports IIRC, so eventually comes to C++ as well.
Balog Pal said:You keep stating that, but why on earth would vector do two allocations? Or
use anything but placement new at all, that for in compiles to nothing...
Again, where does that difference come from?
Please come up with a fair
comparision of the candidates, that do the same thing on the same types, let
the payload struct be POD and your operation a single resize() from the
empty state... Unless certainly you can show different operations the
'hack' can show.
Juha Nieminen said:Compiling that with "g++ -O3 -march=native" on my Pentium4 system takes
about 10 seconds.
You are basing your claims on your personal *opinion*? Rather than,
you know, actually testing it in practice?
It's quite well founded. For example, take this short piece of code:
int main()
{
std::set<int> someSet;
for(int i = 0; i< 10000000; ++i) someSet.insert(i);
}
Juha Nieminen said:How many times does this have to be explained?
If you need to instantiate the struct dynamically, there will be only
one malloc() call if the struct hack is used. However, if the struct hack
is not used, but std::vector or a raw array pointer is used instead, you
will need two allocations: One for the struct and another for the array
inside the struct.
What's so hard to understand in that?
I don't even understand that paragraph.
Juha Nieminen said:You are basing your claims on your personal *opinion*? Rather than,
you know, actually testing it in practice?
It's quite well founded. For example, take this short piece of code:
int main()
{
std::set<int> someSet;
for(int i = 0; i < 10000000; ++i) someSet.insert(i);
}
Compiling that with "g++ -O3 -march=native" on my Pentium4 system takes
about 10 seconds. So, where do you think all that time is spent? Perhaps
rearranging the binary tree each time a new element is inserted? That
sounds
like something which would take its time.
Nope. The majority of that time is spent *allocating memory*.
If you are allocating a million instances of the struct, each such
instance having an std::vector object inside, reserve() would do nothing
to alleviate the memory fragmentation.
Exactly how would boost::array make this any faster? There's no
difference. The issue is not reallocation.
Goran Pusic <[email protected]> wrote:
Nope. The majority of that time is spent *allocating memory*.
If I change the above code to use a very fast memory
allocator, such ashttp://warp.povusers.org/FSBAllocator/so
that the declaration of 'someSet' becomes:
std::set<int, std::less<int>, FSBAllocator<int> > someSet;
then the running time drops down to about 2.5 seconds.
From the 10 seconds running time of the original program above over
7.5 seconds is spent solely on memory allocation and deallocation.
That's quite a *lot*. (There are many reasons why this is so,
one of the major ones being that the default allocator is
thread-safe, which the FSBAllocator above isn't.)
'new' and 'delete' are significantly heavy operations.
Goran said:I am speaking about locality because on current hardware, and in a
running system, it easily makes more difference than allocation. (I am
speaking abut a case where there's not too create-use-destroy cycles,
of course; and IME(xperience), best course of action when there is a
lot of that, are algorithmic changes; OPs hack comes in dead last,
when other options are explored).
Juha said:How many times does this have to be explained?
If you need to instantiate the struct dynamically, there will be only
one malloc() call if the struct hack is used. However, if the struct
hack is not used, but std::vector or a raw array pointer is used
instead, you will need two allocations: One for the struct and
another for the array inside the struct.
What's so hard to understand in that?
The difference comes from the amount of allocations needed.
If you need to instantiate the struct dynamically one million times,
and the struct hack is used, then one million malloc() calls will
suffice. However, if the struct hack is not used, but std::vector or
a raw array pointer is used instead, you will need two million
allocations.
'new' and 'delete' (or malloc() and free()) are quite heavy
operations, so this can have a significant impact in performance. It
also increases memory fragmentation.
I don't even understand that paragraph.
tni said:None of the C or C++ standards allow an array size of 0.
C99 has flexible arrays (which do basically the same thing), but they
are not included in C++03. Unfortunately, it doesn't look like C99
flexible arrays are part of C++0x either. The somewhat good news is
that GCC, Visual C++ 2010 (and presumably Intel C++) do support them.
(GCC and Visual C++ support 0-sized arrays as extension.)
Vladimir said:thomas said:Pete Becker wrote:
Hi, I need your help.
----------
struct SvrList{
unsigned int uNum;
GameSvr svr[0]; //line A
};
---------
Once I declared a struct like this to store server list info.
It's supposed to be used like this.
----------
SvrList* pList = (SvrList*)malloc(sizeof(
SvrList) + svrNum*sizeof(GameSvr));
pList->uNum, pList->svr[0], pList->svr[1].... blabla..
I wouldn't call this fine. Even
pList->svr[0]
is accessing the element that is out of array's bounds, and
that is UB. How come your program is not crashing, or at
least going crazy? Maybe you are just unlucky to have a bug
hidden.
It's an old C programmers hack. I've come across this idiom in
lot's old C code, particularly driver and os code. Microsoft
Win32 is rife with it.
Except that it's not legal C, either.
Which is why it's referred to above as a "hack". Quite a common
one, too.
Usually we use the term "hack" when the code relies on a specific
manifestation of undefined (or unspecified) behavior, but otherwise
is well-formed.
In this case the code is ill-formed, since 0-size array declaration
is illegal in C++ (as well as in C). In other words, arguing about
the "out of bounds" access here doesn't make much sense, since the
code is formally non-compilable.
Wait.. I don't think it's illegal in C++. At least I will definitely
object making it illegal by the standard community.
In the c++ standard, see 8.3.4.1 , this part :
... If the constant-expression (5.19) is present, it shall be an
integral constant expression and its value shall be greater than
zero...
therefore it is illegal c++ code.
It can be dangerous but it can also do good. It depends on whether we
are using it correctly.
Can't use it correctly. It is illegal, therefore undefined behaviour.
Ian Collins said:You are cheating. std::set<int> != std::vector<int> and is in no way an
equivalent to a dynamically allocated array.
Try your test with a vector, before and after reserving space (which is
the more realistic comparison).
Balog Pal said:Hard to decide that your article is a sour attemt at cheating or just basic
trolling. We discuss performance of vector<int> then you insert a snippet
with set<int> like it had any relevance. :-(((
Different collections have different characteristics wrt performance, memory
footprint, etc, we ALL know that. Now please go back to the original claim
instead of drifting in all directions.
And if you allocate a million instances of the struct hack, it will take a
while too. now do you suggest using the struct hack in the *payload*?
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.