Monday, July 16, 2018

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

Jeff-Relf.Me @.: Jul 15 10:09PM -0700

Jeff-Relf.Me @.: Jul 16 06:05AM -0700

Jeff-Relf.Me @.: Jul 16 06:12AM -0700

scott@slp53.sl.home (Scott Lurndal): Jul 15 11:51PM

>to remember to call free when you've finished with the memory. You just
>let the smart pointer go out of scope, and the target vanishes. And this
>happens down all your obscure error paths too.
 
For which there is an inevitable cost. In a recent project, we ripped
out all the smart pointers because they had a huge performance impact. The
code was almost twice as fast after elimination of the smart pointers.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 16 03:47AM +0200

On 16.07.2018 01:51, Scott Lurndal wrote:
 
> For which there is an inevitable cost. In a recent project, we ripped
> out all the smart pointers because they had a huge performance impact. The
> code was almost twice as fast after elimination of the smart pointers.
 
No offense intended, just that it might help you to hear me thoughts here.
 
It seems likely to me that
 
* the smart pointers were not the performance problem, but measuring a
debug build gave nonsense data, and
 
* when the code evolves further the decision to remove smart pointers is
going to bite someone, then, very hard in the ass. Uh, arse. Well, let's
say the "behind", if that's PC. ;-)
 
 
Cheers!,
 
- Alf
Juha Nieminen <nospam@thanks.invalid>: Jul 16 05:19AM

> I seized on the word 'maps' and envisioned something more elaborate than
> your example, involving structs, vectors and maps in various arrangements.
 
Well, freely substitute std::vector with std::map in my example. It doesn't
get any more complicated.
 
Even if you were to use your own custom dynamic data container, its use
still doesn't have to become any more complicated since the language gives
you the tools to make it as simple to use as std::vector and std::map.
 
> trivial as you suggest. A scripting language (even mine which is lower
> level than most) really could handle this stuff trivially and would
> probably run rings around any C++ code.
 
How? A scripting language would probably be slower.
 
Besides, the comparison was to C (and the use of generic data containers
there), not to some other languages.
Juha Nieminen <nospam@thanks.invalid>: Jul 16 05:26AM

> There are very few usage cases for std::list in C++, and I haven't
> encountered any in ~20 years of C++ programming. Each time either
> std::deque or std::vector has been a better fit.
 
It's extremely rare, but sometimes std::list *is* the most convenient
(and, possibly, even most efficient) solution to a problem.
 
Consider, for example, a video game where an enemy shoots tons of
projectiles. These projectiles may hit scenery and objects pretty
much at random, at any moment, with no specific order. The enemy also
spawns new projectiles almost constantly. Therefore new projectiles
are being spawned at a regular basis, and they disappear (and thus
should be removed) pretty much at random.
 
As it turns out, std::list is the most convenient data container
for this. All the projectiles are put into one, and at each frame you
traverse the list and update their positions and check for collisions.
Every time a projectile collides with something and is destroyed, you
can conveniently remove it from the list.
 
In this situation being able to remove the projectile object from the
current position in the list in O(1) is both convenient and efficient
(and may well make up for the slight inefficiency of the memory
allocations needed for the list elements.)
 
The same cannot be efficiently done with a std::vector or std::deque,
where removing the object from it is an O(n) operation.
Paavo Helde <myfirstname@osa.pri.ee>: Jul 16 08:39AM +0300

On 16.07.2018 2:51, Scott Lurndal wrote:
 
> For which there is an inevitable cost. In a recent project, we ripped
> out all the smart pointers because they had a huge performance impact. The
> code was almost twice as fast after elimination of the smart pointers.
 
Then you used wrong type of smartpointers, or used them in a wrong
place. The fact that you were able to rip them out suggests the latter.
 
Inside a std::map implementation for example there are no smartpointers
used as the data structure can manage its data otherwise.
Ian Collins <ian-news@hotmail.com>: Jul 16 06:04PM +1200

On 16/07/18 11:51, Scott Lurndal wrote:
 
> For which there is an inevitable cost. In a recent project, we ripped
> out all the smart pointers because they had a huge performance impact. The
> code was almost twice as fast after elimination of the smart pointers.
 
The only real cost with standard smart pointers in an optimised build
comes from excessive copying of std::shared_ptr objects. On some
targets the resulting atomic increments and decrements are expensive.
That's why it's good practice to pass std::shared_ptr by const reverence
where possible.
 
Using something like std::unique_ptr to manage the lifetime of an object
is a freebie.
 
--
Ian.
Christian Gollwitzer <auriocus@gmx.de>: Jul 16 09:31AM +0200

Am 16.07.18 um 07:26 schrieb Juha Nieminen:
> allocations needed for the list elements.)
 
> The same cannot be efficiently done with a std::vector or std::deque,
> where removing the object from it is an O(n) operation.
 
I'm still not convinced a 100%. To store the projectiles, probably a
small struct can be used which stores the position and velocity. You
could add a single boolean active and pool them. When you want to remove
one, you simply set active to false. Most probably you need to do a full
pass over all of them anyway to test for collisions and update the
position, and inside this loop you can manage and update the active
flag. Compacting the buffer can also be combined with this loop.
 
I think that it still needs to be timed if you win anything by using
std::list instead of a contiguous buffer with occasional reallocation,
i.e. "garbage collection. I agree, however, that std::list is more
convenient.
 
Christian
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 16 10:20AM +0200

On 15.07.2018 15:09, Bart wrote:
>   if c in identstarter then ...
 
> I expect both Python and C++ have a Set implementation so powerful that
> it can do anything - except construct simple sets as easily as above).
 
C++ provides just building blocks. Creating the kind of batteries that
are included with e.g. Python is much work. I took your remark as an
opportunity to yet again code up some set and ranges support in C++.
 
Sort of equivalent code:
 
 
-----------------------------------------------------------------------------
#include <cppx/stdlib-wrappers/Set_.hpp> //
https://github.com/alf-p-steinbach/cppx
#include <stdlib/c/stdio.hpp> //
https://github.com/alf-p-steinbach/Wrapped-stdlib
using namespace std;
 
auto main()
-> int
{
using cppx::Set_;
using cppx::Range_;
 
const auto identstarter = Set_<char>{}
+ Range_{ 'A', 'Z' } + Range_{ 'a', 'z' } + '_' + '$';
const auto identbody = identstarter
+ Range_{ '0', '9' } - 'Z';
 
for( const char ch : Range_{ ' ', char( 127 ) } )
{
if( in( identbody, ch ) )
{
printf( "%c ", ch );
}
}
printf( "\n" );
}
-----------------------------------------------------------------------------
 
 
It's not perfect but it's not so bad either, is it?
 
 
Cheers!,
 
- Alf
boltar@cylonHQ.com: Jul 16 08:39AM

On Fri, 13 Jul 2018 09:09:51 -0700 (PDT)
 
>> C# only runs on windows
 
>No. My music player Roon consists of a Roon Server running on a dedicated
>linux box and a Roon app running on an ipad mini, all using C#.
 
Well ok there's Mono. But its god knows how many versions behind and AFAIK
doesn't support half of the Windows API so whats the point? If you want a VM
language on linux just use java.
boltar@cylonHQ.com: Jul 16 08:42AM

On Fri, 13 Jul 2018 23:27:54 +0100
>to remember to call free when you've finished with the memory. You just
>let the smart pointer go out of scope, and the target vanishes. And this
>happens down all your obscure error paths too.
 
Given C doesn't have exceptions but only explicit returns then remembering
to call free on a local pointer is hardly onorous.
 
>And the copy - once you've taught the object how to copy itself nobody
>else has to mess about with memcpy(target, source, sizeof(type)) then
>fix any embedded pointers.
 
Yes, I'll give you that, but doing deep copies is often a source of bugs
in C++ too. And with the move semantics even more so.
Bart <bc@freeuk.com>: Jul 16 11:20AM +0100

On 16/07/2018 09:20, Alf P. Steinbach wrote:
> }
> -----------------------------------------------------------------------------
 
> It's not perfect but it's not so bad either, is it?
 
No, it doesn't look too bad. (That I could actually follow some C++ for
once is a good sign.)
 
But what is the underlying data-structure? Pascal-like sets might use a
bitmap so the test for 'in' is a simple bit-test (after checking for
range and locating the byte where the bit will be).
 
 
--
bart
Paavo Helde <myfirstname@osa.pri.ee>: Jul 16 03:45PM +0300

On 16.07.2018 13:20, Bart wrote:
>> using cppx::Range_;
 
>> const auto identstarter = Set_<char>{}
>> + Range_{ 'A', 'Z' } + Range_{ 'a', 'z' } + '_' + '$';
[...]
 
> But what is the underlying data-structure? Pascal-like sets might use a
> bitmap so the test for 'in' is a simple bit-test (after checking for
> range and locating the byte where the bit will be).
 
Alf's Set_ is a template probably taking any type which has a comparison
operator defined. C++ has std::bitset which could be used automatically
for a limited range datatype like char. Not sure if this actually a case
or if it would be a good idea at all, too much automatism is not always
good either. Maybe define another class like LimitedRangeSet or something.
 
For comparison, here is a solution using only C++ standard classes. It
requires some helper functions to simplify the usage. As Alf said, C++
tends to give you the building blocks, not the ready-made solution. In a
proper C++ solution these functions should probably go into a custom
class for more encapsulation, this is just a minimal example.
 
#include <iostream>
#include <bitset>
#include <limits>
 
constexpr char kMin = std::numeric_limits<char>::min();
constexpr char kMax = std::numeric_limits<char>::max();
using set = std::bitset<kMax-kMin+1>;
 
set Range(char a, char b) {
set x;
while (a<=b) {
x.set(a++ - kMin);
}
return x;
}
 
set Elem(char a) {
return Range(a, a);
}
 
bool In(char c, const set& x) {
return x[c-kMin];
}
 
int main() {
set identstarter =
Range('A', 'Z') | Range('a', 'z') | Elem('_') | Elem('$');
 
set identbody = (identstarter | Range('0', '9')) & ~Elem('Z');
// exclude Z
 
char c = 'Z';
if (In(c, identstarter)) {
std::cout << c << " is in identstarter\n";
}
if (In(c, identbody)) {
std::cout << c << " is in identbody\n";
}
}
scott@slp53.sl.home (Scott Lurndal): Jul 16 12:51PM


>It seems likely to me that
 
>* the smart pointers were not the performance problem, but measuring a
>debug build gave nonsense data, and
 
Look - all the engineers on the project have a minimum of 20
years experience, each. They do performance analysis of processors
and applications on the scale of operating systems, memcached,
machine learning algorithms and RDBMS systems for a living. I think
we're perfectly capable of doing performance analysis and mitigation
and understanding the difference between production code and whatever
a debug build might be (none of us program on windows systems or use
VS - for us, a debug build omits -O3).
 
The application doesn't do any signficant I/O, so it is very much
CPU-bound.
 
 
>* when the code evolves further the decision to remove smart pointers is
>going to bite someone, then, very hard in the ass. Uh, arse. Well, let's
>say the "behind", if that's PC. ;-)
 
Actually, this is one of the common memes here and in the later C++
versions - you seem to think that
programmers are naturally incompetent and only useless, ill-performing
language enhancements are the solution; whereas the fact is that
programmers have been writing viable, secure and performant C++ code
for three decades without smart pointers, lambdas and other cruft. It's
just not open source.
scott@slp53.sl.home (Scott Lurndal): Jul 16 12:52PM

>where possible.
 
>Using something like std::unique_ptr to manage the lifetime of an object
>is a freebie.
 
So is using a regular pointer and understanding the code.
Manfred <noname@add.invalid>: Jul 16 03:12PM +0200

On 7/16/2018 2:51 PM, Scott Lurndal wrote:
> and understanding the difference between production code and whatever
> a debug build might be (none of us program on windows systems or use
> VS - for us, a debug build omits -O3).
 
Still one question remains: was it unique_ptr or shared_ptr's that you
removed (or both)?
The difference is relevant.
That said, blindly replacing all raw pointers with smart pointers is a
misuse, I agree with you need to know what you are doing and choose
appropriately.
 
(by the way, you know that with gcc omitting -O3 is equivalent to -O0)
 
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 15 08:09PM -0700

On 7/15/2018 7:47 AM, Andrew Goh wrote:
> and that the use of mark and sweep would leave fragmented memory after collection
 
> is there something such as a mark and compact garbage collector? if the simple implementation is difficult perhaps with the combined used of smart pointers?
 
> thanks in advance
 
Think of proxy reference counts:
 
https://groups.google.com/d/topic/lock-free/X3fuuXknQF0/discussion
(read all, if interested...)
 
https://groups.google.com/d/topic/lock-free/QuLBH87z6B4/discussion
 
We can amortize the cost of reference counting by keeping multiple
objects under a proxy reference count. We can take a reference, then
iterate a shi% load of objects without having to mutate anything within
them for they say alive during the iteration. We take a reference, and
read full steam ahead. Fwiw, RCU is an example of a clever proxy
collector optimized for reads, wrt the way it works:
 
https://lwn.net/Articles/262464
(read all!)
 
So, to answer your question, something like RCU can keep everything
alive without a full blown heavy handed garbage collector
 
:^)
bitrex <user@example.net>: Jul 16 01:45AM -0400

On 07/15/2018 10:47 AM, Andrew Goh wrote:
> and that the use of mark and sweep would leave fragmented memory after collection
 
> is there something such as a mark and compact garbage collector? if the simple implementation is difficult perhaps with the combined used of smart pointers?
 
> thanks in advance
 
In C++ at least the ideal is that there is no "garbage" to collect.
Every resource that's "alive" is there for a reason. When the last
context where an object of type Foo needs to exist exits then the
object's destructor is called and all the resources it holds (that the
object ideally acquired via RAII) are freed automatically.
 
E.g. Java needs a garbage collector because there's only one place you
can allocate memory and instantiate resources which is in a heap of some
type; when a function call exits there isn't really a good way to "know"
without some kind of reference counting whether this resource or that in
the heap is still needed? or was it only just used that one time? How do
I know without some fashion of metadata
 
C++ "knows" because unlike Java it has a stack and everything that's not
on the heap is on the stack, and the policy such as it is is that
anything left on the stack when the function call exits is out the door.
The stack is there to be used as much as possible as an option of first
resort; code which uses the operator new/smart pointers to heap-allocate
objects that could fit perfectly well on the stack where the resource is
used only within that function call or a nested set of function calls is
functionally retarded, just do Object object and pass around by
reference or value via the stack, it's cool and fast.
 
IMO whether shared_ptr is 10x slower or not is irrelevant because it has
few good use cases in modern C++, modern C++ which uses it all over the
place is simply not well-designed code. I think I've used it in
something like three or four times. ever.
bitrex <user@example.net>: Jul 16 01:58AM -0400

On 07/16/2018 01:45 AM, bitrex wrote:
> I know without some fashion of metadata
 
> C++ "knows" because unlike Java it has a stack and everything that's not
> on the heap is on the stack
 
Or to be pedantic stuff like constexpr objects could be in read-only
Flash memory or ROM or EEPROM or something in the case of a
Harvard-architecture processor.
Siri Cruise <chine.bleu@yahoo.com>: Jul 16 12:18AM -0700

In article <c85406c3-1cf2-4802-9421-1421fc8720ee@googlegroups.com>,
> than c++ has been around
 
> what's the current state-of-art for 'dynamic' memory management, in the
> notion of *garbage collection*?
 
Same as it has always been:
reference counting
mark sweep
ad hoc
 
reference count:
Cannot cope with cyclic references naively.
Garbage is identified immediately on becoming garbage.
 
mark sweep:
Can collect any kind of reference graph.
Might introduce noticeable pauses during a mark sweep.
 
ad hoc:
Has to be written specifically for each program.
 
> there is Boehm garbage collector
> http://www.hboehm.info/gc/
> is this still very popular or is this commonly being used today?
 
Boehm is a mark/sweep collector. Unlike other such collector it examines memory
without a map locating pointers, so it examines raw words and guesses whether
they are address references.
 
I use it daily.
 
> smart pointers are possibly simply 'good' but i've come across some articles
 
Smart pointers are just a C++ specific technique to sneak in reference counting
(the smart pointer hides the count), mark/sweep (the smart pointer maintains the
list of base pointers), or ad hoc management.
 
> (e.g. AVL trees), complex hash maps / linked lists, in 'objects linked to
> objects' in complex graphs type of scenarios? possibly with circular
> references
 
Only mark/sweep can deal with cycles without any special effort by the
programmer. Reference counting has to have the programmer ensure at least edge
in every cycle is weak. Ad hoc leaves the whole thing to the programmer.
 
> however, bhoehm garbage collector is conservative, and does only mark and
> sweep
 
On 64 bit macosx, the lowest address is 4 billion. Integer values are typically
smaller than this and real values look like extremely high addresses, so
misidentification is rare.
 
> is there something such as a mark and compact garbage collector? if the
> simple implementation is difficult perhaps with the combined used of smart
> pointers?
 
A compactor has to be able to update all pointers which tends to be lannguage
specific. With hundreds of gigabytes of virtual memory, fragmentation is less
of a concern.
 
--
:-<> Siri Seal of Disavowal #000-001. Disavowed. Denied. Deleted. @
'I desire mercy, not sacrifice.' /|\
I'm saving up to buy the Donald a blue stone This post / \
from Metebelis 3. All praise the Great Don! insults Islam. Mohammed
Andrew Goh <andrewgoh0@gmail.com>: Jul 16 05:52AM -0700

hi all,
thanks for all the responses, actually coming from the java world c++ is quite as 'native' to me, i'd guess most 'java programmers' (and so do other similar managed languages) are somewhat spoilt by garbage collection.
 
i'm coming back into c++ for various reasons among which modern multi-core processors increasingly have features that 'high level' languages such as java can only depend on jvm, compiler to 'optimise' the 'low level' codes. one has little influence over if jvm, compiler etc would after all use the features.
things that come to mind are the various SIMD, AVX, AVX2, AVX512 instructions and increasingly GPUs as well
 
c++ can use various processor intrinsics, link manual assembler optimised object files, link processor optimised libraries e.g. MKL or TBB
https://www.threadingbuildingblocks.org/
or even link as a cilk+ module, which probably make codes more portable and readable with all that vector optimizations
 
thanks for the notes on smart pointers and bhoehm gc i'd certainly try them out
https://www.cilkplus.org/
Storage Unit <storage.unit@mailinator.com>: Jul 15 10:01PM -0500

> ....
> if ( Msg.message == WM_HOTKEY && Msg.wParam == 'K' )
> Launch( L"/Program Files/Common Files/microsoft shared/ink/TabTip.EXE" ),
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Things like that are the reason why Windows programs suddenly break when
something is not installed to default location.
 
By the way, Jeff, why no HTML posts anymore?
 
 
--
Emacs OS
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 15 08:50PM -0700

On 7/15/2018 1:38 AM, Hergen Lehmann wrote:
> different and my understatement of the rather complex IOCP may not be
> good enough to fully utilize its power. Although a windows expert
> consulted back than did not find anything, i'm doing totally wrong...
 
Fwiw, I used to work with IOCP all the time back in WinNT 4.0.
 
It can scale. However, it has some interesting quirks.
 
https://groups.google.com/d/msg/comp.lang.c++/kAz1VAxD2lI/WqeBMQZtAwAJ
 
https://groups.google.com/forum/#!topic/comp.lang.c++/kAz1VAxD2lI/overview
(read all, there is an interesting discussion about IOCP in there...)
 
https://msdn.microsoft.com/en-us/library/windows/desktop/aa365683(v=vs.85).aspx
 
(read all)
 
The system is fairly nice. Love the following function:
 
https://docs.microsoft.com/en-us/windows/desktop/FileIO/getqueuedcompletionstatusex-func
 
Grab a bunch of completions at once! Not available back then in nt4.
Argh! ;^)
 
 
 
You received this digest because you're subscribed to updates for this group. You can change your settings on the group membership page.
To unsubscribe from this group and stop receiving emails from it send an email to comp.lang.c+++unsubscribe@googlegroups.com.

No comments: