Thursday, June 10, 2021

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

David Brown <david.brown@hesbynett.no>: Jun 10 09:44AM +0200

On 09/06/2021 23:10, Real Troll wrote:
> On 09/06/2021 20:23, Öö Tiib wrote:
>> Censoring Internet. :D Smells like North Korea. Did U.S. have Communist
>> coup d'état ?
 
<snip>
 
Please don't try to start political wars here. This is an international
group, not an American group, and it is for C++, not a politics group.
 
Comments about the group's removal from Google Groups, and what (if
anything) can be done to reverse that are on topic. General discussions
about censorship, for or against, are not.
 
If you want to talk politics in a technical group, go to
sci.electronics.design. It is a discussion group for politics,
religion, etc., with an occasional thread on electronics. But put on
your asbestos underwear first - some of the regulars there are really
unpleasant characters.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Jun 10 07:56AM -0700


> <snip>
 
> Please don't try to start political wars here. This is an international
> group, not an American group, and it is for C++, not a politics group.
 
The name "Real Troll" should be a clue that this person is not going to
pay attention to complaints. The solution is left as an exercise for
your killfile.
 
[snip]
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips Healthcare
void Void(void) { Void(); } /* The recursive call of the void */
Real Troll <real.troll@trolls.com>: Jun 10 05:13PM

On 10/06/2021 08:44, David Brown wrote:
> <snip>
 
> Please don't try to start political wars here. This is an international
> group, not an American group, and it is for C++, not a politics group.
 
Please don't attribute anything to people when they didn't post what you
attributed here.  Attention to detail is a must in these newsgroups.  If
you want to carelessly accuse people than there are other newsgroups
such as " misc.survivalism ".
Real Troll <real.troll@trolls.com>: Jun 10 05:27PM

On 10/06/2021 15:56, Keith Thompson wrote:
> The solution is left as an exercise for
> your killfile.
 
 
Can you kill file me too, please? I promise to offend you. All drama
queens find me offensive.
"Öö Tiib" <ootiib@hot.ee>: Jun 10 03:17PM -0700

On Thursday, 10 June 2021 at 10:44:43 UTC+3, David Brown wrote:
> religion, etc., with an occasional thread on electronics. But put on
> your asbestos underwear first - some of the regulars there are really
> unpleasant characters.
 
Estonia was still part of Communist country when I first reached Usenet
using modem, phone, and calling to number of KTH Royal Institute of
Technology in Sweden that also involved some tricks that weren't legal
by local legislature. So it is symbolic for me and attempts to censor
it are also symbolic for me and discussing it is not Real Troll's fault
but mine.
Lynn McGuire <lynnmcguire5@gmail.com>: Jun 10 04:59PM -0500

Is there a good reference on threads ? I would like to delegate the
writing of our binary file to a background thread if possible. Our
Win32 Windows desktop program is mostly MFC with about 450,000 lines of
C++ code.
 
I do suspect that this is not doable, due to the nature of the data
being used for dialogs and such.
 
Thanks,
Lynn
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 12:18PM +0200

vector is specified to have a amortized constant overhead for inserting
new elements. Because of that ::emplace_back() et al grow the capacity
exponentiallly if necessarsy (2x for libstdc++, 1.5x for MSVC). But why
does this not apply for vector::reserve() ? It could simply handle the
reservations in a way that the increase which should be made is below
the next exponential step, the given size doesn't count but the next
anticipated step. That would be the most logical way for me to handle
this issue.
Bo Persson <bo@bo-persson.se>: Jun 10 01:21PM +0200

On 2021-06-10 at 12:18, Bonita Montero wrote:
> the next exponential step, the given size doesn't count but the next
> anticipated step. That would be the most logical way for me to handle
> this issue.
 
I believe the idea is that you use reserve() when you have a good idea
of what the final size is likely to be.
 
I wouldn't want the implementation to allocate 50-100% additional space
just in case the vector would continue to grow. Presumably, when calling
reserve() I know that it will not.
Paavo Helde <myfirstname@osa.pri.ee>: Jun 10 02:37PM +0300

10.06.2021 13:18 Bonita Montero kirjutas:
> new elements. Because of that ::emplace_back() et al grow the capacity
> exponentiallly if necessarsy (2x for libstdc++, 1.5x for MSVC). But why
> does this not apply for vector::reserve() ?
 
Because reserve() is only needed for the case when the default
exponential growth is not appropriate for some reason. If so, only the
programmer can know how it's not appropriate and how the buffer should
grow. So there would be little point to double-guess it and do something
else automatically.
 
> reservations in a way that the increase which should be made is below
> the next exponential step, the given size doesn't count but the next
> anticipated step.
 
I'm not sure I understand this sentence.
 
> That would be the most logical way for me to handle
> this issue.
 
What issue?
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 03:44PM +0200

> Because reserve() is only needed for the case when the default
> exponential growth is not appropriate for some reason. ...
 
The standard says:
"After reserve(), capacity() is _greater or equal_
to the argumentof reserve if reallocation happens ..."
So the standard gives the vector-implementation the freedom to grow
beyond the size you supply with resize(). I think that's because the
vector has to satisfy the amortized constant inserts.
David Brown <david.brown@hesbynett.no>: Jun 10 04:39PM +0200

On 10/06/2021 15:44, Bonita Montero wrote:
> So the standard gives the vector-implementation the freedom to grow
> beyond the size you supply with resize(). I think that's because the
> vector has to satisfy the amortized constant inserts.
 
No, that would make no sense. It is simply to allow the implementation
to round up the capacity a bit if that suits the memory allocator -
perhaps it allocates in lumps of 4K, or cache aligned sizes, or
something else that means when you ask for space for 19 elements it
might give you 24 elements.
 
You use "reserve" when you know how your vector will grow, because it is
more efficient to jump to the right size than grow exponentially. If
you know you are going to store 1000 elements, you reserve space for
1000 (and don't care if the implementation sets the actual capacity to
1024). That is far faster than starting with 1 element and doubling 10
times, or scaling by 1.5 in 17 steps.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 04:47PM +0200

> No, that would make no sense. It is simply to allow the implementation
> to round up the capacity a bit if that suits the memory allocator - ...
 
There are no rounding memory-allocators. You say the allocator you
want size = n * sizeof(type) memory and it gives you the memory and
the allocator-API doesn't give you the opportunity to get the size
actually allocated. So you're wrong.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 04:51PM +0200

That's the API:
https://en.cppreference.com/w/cpp/memory/allocator/allocate
Where do you get the opportunity to get the size of the
actually logically or physically allocated memory ?
MrSpook_sw@08_cl170xu11o4f8xcg45.co.uk: Jun 10 03:25PM

On Thu, 10 Jun 2021 16:39:13 +0200
>perhaps it allocates in lumps of 4K, or cache aligned sizes, or
>something else that means when you ask for space for 19 elements it
>might give you 24 elements.
 
I always thought vector was a bit of a mess with reserve(), resize(),
capacity() and size(). Having reserve() that allocates the array slots but
not the objects in them so allowing a valid [] access into the reserved but
uninitialised indexes which then gives indefined behaviour with non simple
types is IMO something that should be flagged as Use With Extreme Caution.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 06:18PM +0200

> not the objects in them so allowing a valid [] access into the reserved but
> uninitialised indexes which then gives indefined behaviour with non simple
> types is IMO something that should be flagged as Use With Extreme Caution.
 
That's not what we're talking about. The discussion is about how much
reserve() actually allocates, not whether you can access objects behind
size() but within capacity().
Paavo Helde <myfirstname@osa.pri.ee>: Jun 10 10:40PM +0300

> not the objects in them so allowing a valid [] access into the reserved but
> uninitialised indexes which then gives indefined behaviour with non simple
> types is IMO something that should be flagged as Use With Extreme Caution.
 
Do you realize that calling reserve() and capacity() is fully optional?
If you do not like them, just don't use these functions.
 
And from where did you get the idea that accessing the vector beyond its
size is valid for POD types? It's definitely UB and I bet there are
debugging implementations which abort the program when they detect this
(aborting the program is a perfect example of UB).
Bo Persson <bo@bo-persson.se>: Jun 10 10:00PM +0200

On 2021-06-10 at 16:47, Bonita Montero wrote:
> want size = n * sizeof(type) memory and it gives you the memory and
> the allocator-API doesn't give you the opportunity to get the size
> actually allocated. So you're wrong.
 
A standard library for a specific system will just *know* that the
memory allocator is pooled and works in certain chunks.
 
For example, if you ask for size = 1 * sizeof(char), you will never get
a single byte. You will get 16 bytes.
 
It is then just rational for reserve(1) to result in capacity == 16.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 10:09PM +0200

> A standard library for a specific system will just *know* that the
> memory allocator is pooled and works in certain chunks.
 
This is the requirement for a container-compliant allocator:
https://en.cppreference.com/w/cpp/named_req/Allocator
Where's the interface that supplies the container the real
size of an allocated memory-block ?
"Alf P. Steinbach" <alf.p.steinbach@gmail.com>: Jun 10 10:35PM +0200

On 10 Jun 2021 21:40, Paavo Helde wrote:
> size is valid for POD types? It's definitely UB and I bet there are
> debugging implementations which abort the program when they detect this
> (aborting the program is a perfect example of UB).
 
Depends what the guy meant.
 
After a `.reserve` there is a guaranteed contiguous buffer of
`.capacity` size. With a vector size of at least 1 one can obtain a raw
pointer to it via `data`, and index that pointer.
 
You'd need the legendary perverse implementation with phat pointers, to
detect that.
 
 
- Alf
Tim Rentsch <tr.17687@z991.linuxsc.com>: Jun 10 11:29AM -0700

> size_t variable or copying this memory range somewhere. At best you
> could copy a tail of the DS segment and the head of the ES segment
> somewhere, but why not vice versa?
 
Yes, as a practical matter no actual C++ implementation is
going to accommodate objects that cross a segment boundary.
 
My question though was about what the C++ standard allows for
pointers into a single struct object (of the contiguous
variety). I know that C does allow pointer arithmetic for
such pointers (ie, character pointers), but my efforts to
discover whether the C++ standard allows it have not been
successful.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 06:45PM +0200

I can have multiple overloads of a function for multiple concept
-types:
 
#include <concepts>
 
using namespace std;
 
template<floating_point Fp>
void f( Fp fp )
{
}
 
template<integral Int>
void f( Int i )
{
}
 
But how can I do that with structs / classes - so I would have
multiple specializations of a class for different concept-types.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 06:49PM +0200

Oh, I got it:
 
template<typename T>
struct S
{
};
 
template<integral Int>
struct S<Int>
{
};
 
template<floating_point Fp>
struct S<Fp>
{
};
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 04:31AM +0200

> Well, there's no such guarantee in the standard.
 
I'm dealing with Windows-compilers, so the standard doesn't count.
 
> But for 64-bit Windows programming you should be safe: 1 calling
> convention to rule them all.
 
With 32-bit Windows the calling-operator is individually compiled
for each call if you have different calling-conventions.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 04:47AM +0200

>> Well, there's no such guarantee in the standard.
 
> I'm dealing with Windows-compilers, so the standard doesn't count.
 
Here, test it yourself on Windows 32 Bit:
 
#include <iostream>
 
using namespace std;
 
int main()
{
thread_local
int volatile i = 0;
auto lambda = []( int add )
{
i += add;
};
void (__stdcall *volatile fs)( int ) = lambda;
void (__fastcall *volatile ff)( int ) = lambda;
fs( 123 );
ff( 456 );
cout << (void *)fs << endl;
cout << (void *)ff << endl;
}
 
The lambda-function is compiled twice here.
Bonita Montero <Bonita.Montero@gmail.com>: Jun 10 11:38AM +0200

>     cout << (void *)ff << endl;
> }
> The lambda-function is compiled twice here.
 
Unfortunately that doesn't work with clang-cl, the clang-variant
that claims to be mostly MSVC-compatible. I found this incompati-
bility documented from 2018 on the clang-devel mailinglist. I'm
asking why this hasn't been fixed yet - compiling the lamdda with
multiple calling-conventions shouldn't be a big deal.
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: