Tuesday, January 27, 2015

Digest for comp.lang.c++@googlegroups.com - 25 updates in 5 topics

Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 27 12:25AM

On Mon, 26 Jan 2015 16:30:24 -0600
 
> I'd sure like to know how the author intended to use this class,
> because I question both making it static and using the c-array vs a
> stl container.
 
Clearly there is a use case for a statically sized container with
contiguous storage or std::array would not be in C++11. And if the
array is a non-static class member, it makes little difference whether
you use a plain array or std::array because both have the same compiler
generated copy constructor and assignment operator. That use case
generally involves efficiency, because unlike std::vector arrays are
not dynamically allocated (unless you explicitly new them, which is
stupid because std::vector is available). For the cases I have
mentioned, I use a plain array, partly because that is what I have done
for years, and partly because ... why not?
 
std::array permits a zero size and a plain array does not, but I have
never written code requiring a zero size array.
 
Whether it should be static member or not is orthogonal. If it is a
static member, it is of even less importance whether it is a plain
array or a std::array type. And maybe of course the OP was using
C++98/03.
 
Chris
Christopher Pisz <nospam@notanaddress.com>: Jan 26 06:43PM -0600

On 1/26/2015 6:25 PM, Chris Vine wrote:
> stupid because std::vector is available). For the cases I have
> mentioned, I use a plain array, partly because that is what I have done
> for years, and partly because ... why not?
 
I often hear that same argument from C programmers: "std::vector
allocates." If you are using a c-array, you must know the size before
hand, and if you know the size before hand, you can create the vector
with that size, so what are we really optimizing away in the name of
efficiency?
 
I suppose you could argue the one time allocation on the heap at
construction time vs on the stack, if your class resides on the stack
anyway. However, what are you really saving and what are you giving up?
 
 
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 27 12:57AM

On Mon, 26 Jan 2015 18:43:56 -0600
Christopher Pisz <nospam@notanaddress.com> wrote:
[snip]
> construction time vs on the stack, if your class resides on the stack
> anyway. However, what are you really saving and what are you giving
> up?
 
That is ridiculous. Allocation on the heap is a heavy-weight
operation compared with allocation on the stack, relatively speaking,
particularly in multi-threaded programs which require thread-safe
allocation and deallocation. Dynamic allocation also reduces cache
locality. Furthermore std::vector constructed with a particular
initial size calls the default constructor for each element, so you
sometimes have to reserve a size and then pushback onto it to avoid
that.
 
Are you seriously saying that in your code you always use std::vector
instead of an array even when the size is known statically? And why do
you think std::array is in C++11?
 
The case for using std::vector even with statically known sizes is when
you may carry out move operations, as moving vectors just requires
swapping pointers. But you would still need to profile.
 
I find your question disturbing.
 
Chris
Ian Collins <ian-news@hotmail.com>: Jan 27 08:09PM +1300

Christopher Pisz wrote:
 
> I suppose you could argue the one time allocation on the heap at
> construction time vs on the stack, if your class resides on the stack
> anyway. However, what are you really saving and what are you giving up?
 
Locality of reference?
 
--
Ian Collins
Juha Nieminen <nospam@thanks.invalid>: Jan 27 08:21AM

> After all the discussion of profiling and virtual functions in child
> threads, ....I still want to know why in the world anyone would want a
> static C-Array in their C++ class.
 
Because it's enormously more efficient.
 
It's faster to allocate and deallocate (allocating memory for the array
doesn't take any more additional time than allocating the instance of
the class the array is inside). It consumes less memory. It does not
contribute to memory fragmentation.
 
Sure, in a class that's instantiated a few times it doesn't matter.
However, in a class that's instantiated tens of thousands, or even
millions of times, it matters quite a lot.
 
--- news://freenews.netfront.net/ - complaints: news@netfront.net ---
David Brown <david.brown@hesbynett.no>: Jan 27 11:23AM +0100

On 27/01/15 01:43, Christopher Pisz wrote:
> hand, and if you know the size before hand, you can create the vector
> with that size, so what are we really optimizing away in the name of
> efficiency?
 
1.
 
Allocating a block of data on the stack takes a couple of instructions -
allocating it in heap can mean system calls, locks, threading issues,
etc. (Typically a new/malloc implementation holds a local pool that can
be quickly allocated, and only needs a system malloc to re-fill the
local pool - so allocation times can vary between "not much" to "a lot",
depending on the state of the local pool.)
 
And allocating a block statically takes no instructions at all.
 
If you are doing this once, dynamic allocation of a vector means wasting
a few microseconds, which is obviously not a concern. But if you are
doing it thousands of times, it adds up.
 
2.
 
Static allocation, or at least stack allocation, is far more amenable to
compile-time checking and (if necessary) faster run-time checks to help
catch errors sooner.
 
3.
 
Statically allocated data, or at least stack allocated data, requires
fewer instructions and fewer registers to access, making it faster. It
also has better locality of reference and is more likely to be in the
cache, which can make a huge difference (this depends on the size of the
data and the access patterns, of course).
 
 
Coming from an embedded background, where this is often much more
relevant than on desktop systems (partly because memory fragmentation on
heaps is a serious issue when you don't have virtual memory), there is a
clear golden rule that all allocations should be static if possible,
with stack allocation as a second-best. In many embedded systems,
dynamic allocation is not allowed at all - it is certainly never encouraged.
 
Christopher Pisz <nospam@notanaddress.com>: Jan 27 09:28AM -0600

On 1/27/2015 4:23 AM, David Brown wrote:
 
> If you are doing this once, dynamic allocation of a vector means wasting
> a few microseconds, which is obviously not a concern. But if you are
> doing it thousands of times, it adds up.
 
 
Well, this is what I am getting at. If there is _one_ allocation, there
is no need to apply a rule of "I won't use any STL container, because
allocation!", which is often what I hear from C programmers. More often
than not A) They are not even aware you can specify size at construction
time for a vector or reserve size after if you wish B) They haven't even
considered how often the container or class that owns the container is
being constructed.
 
 
> Static allocation, or at least stack allocation, is far more amenable to
> compile-time checking and (if necessary) faster run-time checks to help
> catch errors sooner.
 
What exactly does "amenable to compile time checking" mean?
 
"Run time checks to catch errors sooner?" What run time check is going
to occur on a c-array? Run time checks would be a reason to use an STL
container in the first place. Of course none is faster than some.
 
 
> also has better locality of reference and is more likely to be in the
> cache, which can make a huge difference (this depends on the size of the
> data and the access patterns, of course).
 
Not disagreeing with you, but I've never read any evidence of a
contiguous block of memory on the stack vs a contiguous block of memory
on the heap being more likely to be in the cache. Have anything to
reference?
 
> clear golden rule that all allocations should be static if possible,
> with stack allocation as a second-best. In many embedded systems,
> dynamic allocation is not allowed at all - it is certainly never encouraged.
 
Well, that's the thing. I often work with C programmers whom came from a
background where it was relevant, but then they adopt silly rules like
"don't ever use an STL container, because 'allocation'" in places where
the difference is negligible.
 
You do, but I have my doubts that the OP did. I am willing to bet he was
doing what he did, "just because", but we'll never know.
 
Christopher Pisz <nospam@notanaddress.com>: Jan 27 09:40AM -0600

On 1/26/2015 6:57 PM, Chris Vine wrote:
>> up?
 
> That is ridiculous. Allocation on the heap is a heavy-weight
> operation compared with allocation on the stack,
 
No one is arguing otherwise.
 
The thing I have a problem with is I often end up working with people
whom use that as an excuse to never use an STL container at all,
regardless of how often allocation may occur.
 
 
> relatively speaking,
> particularly in multi-threaded programs which require thread-safe
> allocation and deallocation.
 
std::vector<int>(10) is going to be the same whether my program is
multithreaded or not.
 
If there are thread safety concerners, then most likely the container
would be inside some class and the same locking mechanisms are going to
be added whether it is a std::vector, a c-array, or a snuffleupugus.
 
> Dynamic allocation also reduces cache
> locality.
 
Someone else said this too. Not disagreeing, but I've never read it. Got
a reference?
 
> initial size calls the default constructor for each element, so you
> sometimes have to reserve a size and then pushback onto it to avoid
> that.
 
but again, how long does it take to construct an int? It depends on the
scenario and like I said, I suspect the OP was doing what he was doing
just because "Me like meat. STL bad....C gud.", but looks like he lost
interest in his topic.
 
 
 
 
 
 
 
 
 
 
jak <please@nospam.tnx>: Jan 27 05:38PM +0100

Il 27/01/2015 16:40, Christopher Pisz ha scritto:
> scenario and like I said, I suspect the OP was doing what he was doing
> just because "Me like meat. STL bad....C gud.", but looks like he lost
> interest in his topic.
 
I have not lost interest, indeed, I follow you with attention. my
problem was to serialize a resource. I use the static field in the class
to save the state of the resource even when I declare a new variable of
that class in the various functions to always know the situation of the
resource.
 
PS:
I had to cut the rest of the discussion because my application gave me a
sending error. sorry.
Christopher Pisz <nospam@notanaddress.com>: Jan 27 11:04AM -0600

On 1/27/2015 10:38 AM, jak wrote:
 
> PS:
> I had to cut the rest of the discussion because my application gave me a
> sending error. sorry.
 
 
Oh , I thought some fellow named Alessio was the OP. You are using 2
different accounts then I suppose.
Chris Vine <chris@cvine--nospam--.freeserve.co.uk>: Jan 27 07:51PM

On Tue, 27 Jan 2015 09:40:12 -0600
> would be inside some class and the same locking mechanisms are going
> to be added whether it is a std::vector, a c-array, or a
> snuffleupugus.
 
That's not the point. The heap is a global resource and the _heap
manager_ has to deal with concurrency in a multi-threaded program. This
has nothing to do with concurrent access to the same container (if you
are going to have concurrent access to the same container you need to at
least look at std::list if you are going to have a lot of contention).
The fact that the heap manager has to cope with concurrency is one of
the reasons why dynamic allocation has overhead.
 
> > locality.
 
> Someone else said this too. Not disagreeing, but I've never read it.
> Got a reference?
 
I cannot come up with a study (although I would be surprised if there
wasn't one), but it must do so, because memory allocated on the heap
will not be in the same cache line as the memory for the object itself.

> the scenario and like I said, I suspect the OP was doing what he was
> doing just because "Me like meat. STL bad....C gud.", but looks like
> he lost interest in his topic.
 
It's the cost of unnecessary zero initialization of built in types.
Small, but it is there and if you can avoid it then why not?
 
I just come back to the point that failing to make use of an array (or
std::array) instead of std::vector where you have a statically
(constexpr) sized container of built in types, just because you don't
like C programming practices, seems crazy to me. It's a bit like
failing to call std::reserve() on a vector when you actually know
programmatically at run time what the final size of the vector will be,
and instead just relying on the vector's normal algorithm to allocate
memory in multiple enlarging steps as it is pushed onto. The code will
still work but you will be doing unnecessary allocations of memory and
copying or moving of vector elements. Don't do it if you can avoid it.
 
Take the low hanging fruit. It is not premature optimization to follow
a few simple rules which will make all your programs faster without any
extra effort.
 
Chris
Christopher Pisz <nospam@notanaddress.com>: Jan 27 12:54PM -0600

Is there some defined standard behavior about what should happen should
an Access Violation occur on a thread?
 
My application is single threaded, and I see in my debugger it has 12 or
so threads with COM and RPC and wininet crap. Everything in those
threads is completely outside of my source. So, I assume some third
party library (gsoap) is creating these threads. Randomly I get an
Access Violation on one or more of these threads.
 
Should I expect the process to terminate?
or
Should the thread terminate on its own?
 
What is expected to happen if this occurs?
Paavo Helde <myfirstname@osa.pri.ee>: Jan 27 01:34PM -0600

Christopher Pisz <nospam@notanaddress.com> wrote in news:ma8mse$gv4$1
 
> Is there some defined standard behavior about what should happen should
> an Access Violation occur on a thread?
 
> My application is single threaded, and I see in my debugger it has 12
or
> or
> Should the thread terminate on its own?
 
> What is expected to happen if this occurs?
 
Access violation is most usually caused by the program invoking Undefined
Behavior, so anything can happen. Typically, in Linux world you could be
pretty certain the process is killed in spot by the OS. However, in
Windows world this is not so simple, the program can define handlers for
"handling" these kind of errors. Windows also likes to display (mostly
unhelpful) dialog boxes, sometimes offering a possibility to attach a
debugger. As "anything can happen", all these behaviors are legal.
 
Terminating a single thread is not an option as this is pretty much
guaranteed to leave the process in an inconsistent state.
 
Another a bit more reliable way is to "handle and ignore" the error,
there are even Windows SDK idioms which actually do that in an
encapsulated way (IsBadReadPtr() and friends) which can be greatly abused
by crappy programs for hiding their bugs. If you can continue the program
in the debugger after the access violation and nothing bad seems to
happen, this probably means the code has "handled" the access violation
in this or a similar way.
 
Note that even if the problem appears in a foreign thread it does not
mean that your code is not to blame. It could have passed some invalid
data to the foregin thread directly or indirectly.
 
hth
Paavo
DSF <notavalid@address.here>: Jan 26 11:41PM -0500

On Mon, 26 Jan 2015 21:57:06 +0000 (UTC), Tobias Müller
 
>> Borland C/C++ 5.01A
 
>> Yes, I know.
 
>Do you realize that this is almost 20 years old?
 
LOL! LOL! LOL! LOL!
 
No offense meant, but thanks for the laugh! I have broken or at
least severely bent causality by answering your question before you
asked it, i.e. effect -> cause.
 
>Tobi
 
DSF
"'Later' is the beginning of what's not to be."
D.S. Fiscus
DSF <notavalid@address.here>: Jan 27 03:22AM -0500

On Sun, 25 Jan 2015 14:28:05 -0500, DSF <notavalid@address.here>
wrote:
 
>Hello, group!
 
I should mention in the very slight defense off my 25-year-old
compiler that it does also highlight the line with the error and list
its approximate location before the error.
! FAList.h(530,1):Illegal structure operation
 
So I know what template it is in and I can translate the error to
"The == operator is not a standard operator that can be used with
structures (classes)." Meaning I have an instance somewhere of
FAList<some_class> foo, where some_class has not overloaded ==. My
problem being the message doesn't identify "some_class".
 
I can't afford the time right now to learn my way around a new
compiler. Not to mention all the source I'll have to recompile. And
even though I have all warnings and errors enabled in my current
moldy-oldie, I'm sure there will be *many* lines of code indigestible
to the new compiler without tweaking.
 
In fact, I have a compiler ready for installation in a virtual
machine, but I need the use of the utility I'm writing (the one with
this error) to have the disk space to set up the virtual machine.
 
I've searched every file in the project and associated libraries for
FAList< and every instance the class inside the angle brackets has an
overloaded ==. I did encounter something unusual. I'll summarize it:
 
class Foo
{
public:
...etc...
friend bool operator==(const Foo& foo1, const Foo& foo2);
...
};
 
inline bool operator==(const Foo& foo1, const Foo foo2)
{do comparison};
 
Note the missing ampersand on the second Foo of the inline line.
Shouldn't this be an error? The TU compiled with 0 errors and 0
warnings. BTW, adding the ampersand did not fix the main problem.
 
Thanks for all your responses,
DSF
"'Later' is the beginning of what's not to be."
D.S. Fiscus
Rosario193 <Rosario@invalid.invalid>: Jan 27 09:23AM +0100

On Mon, 26 Jan 2015 16:00:28 -0500, DSF wrote:
...
 
>DSF
>"'Later' is the beginning of what's not to be."
>D.S. Fiscus
 
this compile and run here...
#include <stdio.h>
 
class Foo
{public:
Foo(int n): num(n){;}
Foo(Foo& a){if(&a!=this) num=a.num;}
friend int operator==(Foo& f1, Foo& f2);

int num;
};
 
int operator==(Foo& f1, Foo& f2){return f1.num==f2.num;}
 
template<class T>class Tester
{public:
int CompareObject(T& obj){return object==obj;}
Tester(T& obj):object(obj){;}
 
T object;
};
 
 
int main(void)
{Foo fo1(12);
Foo fo2(12);
Tester<Foo> testfoo(fo1);
int result=testfoo.CompareObject(fo2);

printf("fo1 %s equal fo2\n", result ? "does" : "does not");
return 0;
}
Rosario193 <Rosario@invalid.invalid>: Jan 27 10:05AM +0100

On Tue, 27 Jan 2015 09:23:33 +0100, Rosario193 wrote:
 
 
> printf("fo1 %s equal fo2\n", result ? "does" : "does not");
> return 0;
>}
 
_TEXT segment dword public use32 'CODE'
@$beql$qr3Foot1 segment virtual
@@$beql$qr3Foot1 proc near
?live16385@0:
;
; int operator==(Foo& f1, Foo& f2){return f1.num==f2.num;}
;
push ebp
mov ebp,esp
@1:
mov eax,dword ptr [ebp+8]
mov edx,dword ptr [eax]
mov ecx,dword ptr [ebp+12]
cmp edx,dword ptr [ecx]
sete al
and eax,1
@3:
@2:
pop ebp
ret
@@$beql$qr3Foot1 endp
@$beql$qr3Foot1 ends
_TEXT ends
_TEXT segment dword public use32 'CODE'
_main segment virtual
@_main proc near
?live16386@0:
;
; int main(void)
;
push ebp
mov ebp,esp
add esp,-12
;
; {Foo fo1(12);
;
@4:
mov dword ptr [ebp-4],12
;
; Foo fo2(12);
;
mov dword ptr [ebp-8],12
;
; Tester<Foo> testfoo(fo1);
;
lea eax,dword ptr [ebp-4]
lea edx,dword ptr [ebp-12]
cmp eax,edx
je short @5
mov ecx,dword ptr [ebp-4]
mov dword ptr [ebp-12],ecx
 
here appear that is called
"Foo(Foo& a){if(&a!=this) num=a.num;}"
inline
 
;
; int result=testfoo.CompareObject(fo2);
;
@5:
@6:
lea eax,dword ptr [ebp-8]
push eax
lea edx,dword ptr [ebp-12]
push edx
call @@$beql$qr3Foot1
add esp,8
 
here it call the right function
int operator==(Foo& f1, Foo& f2){return f1.num==f2.num;}
 
and printf result:
 
;
;
; printf("fo1 %s equal fo2\n", result ? "does" : "does not");
;
?live16386@80: ; EAX = result
test eax,eax
je short @7
mov ecx,offset s@+18
jmp short @8
@7:
mov ecx,offset s@+23
@8:
push ecx
push offset s@
call @_printf
add esp,8
;
; return 0;
;
?live16386@96: ;
xor eax,eax
;
; }
;
@10:
@9:
mov esp,ebp
pop ebp
ret
@_main endp
_main ends
Bo Persson <bop@gmb.dk>: Jan 27 12:17PM +0100

On 2015-01-27 09:22, DSF wrote:
 
 
> Note the missing ampersand on the second Foo of the inline line.
> Shouldn't this be an error? The TU compiled with 0 errors and 0
> warnings.
 
That's a different operator that doesn't match the friend declaration.
It will compare foo1 against a copy of foo2, but is perfectly legal.
 
 
> BTW, adding the ampersand did not fix the main problem.
 
Too bad.
 
 
Bo Persson
Louis Krupp <lkrupp@nospam.pssw.com.invalid>: Jan 27 07:23AM -0700

On Mon, 26 Jan 2015 16:00:28 -0500, DSF <notavalid@address.here>
wrote:
 
> printf("fo1 %s equal fo2\n", result ? "does" : "does not");
> return 0;
>}
 
Is it possible that this has nothing to do with templates? Compiling
this code with -c seems to reproduce the problem:
 
===
class Foo
{
public:
Foo() : num(0){};
 
int num;
};
 
#if 0
bool operator==(const Foo& f1, const Foo& f2)
{
return f1.num == f2.num;
}

No comments: