Thursday, July 19, 2018

Digest for comp.lang.c++@googlegroups.com - 19 updates in 7 topics

Paavo Helde <myfirstname@osa.pri.ee>: Jul 19 10:43PM +0300

On 19.07.2018 20:28, David Brown wrote:
 
> It interests embedded programmers too. If you have a fixed size of code
> flash on a device, and your program is nearing that limit, size begins
> to matter a great deal.
 
Well, then you compile with -Os or equivalent, and hope the compiler
does the right thing and optimizes for the size. AFAIK there are even
special compilers for embedded devices which can create smaller binaries.
 
In case of exception handling this means you trade some speed for the
size. TANSTAAFL.
 
When you do compile without -Os then it means you do not care about the
size. Maybe I should have been more clear I was talking about that regime.
 
[snipping the rest because my killfile has eaten the parent post]
David Brown <david.brown@hesbynett.no>: Jul 20 12:27AM +0200

On 19/07/18 21:43, Paavo Helde wrote:
>> to matter a great deal.
 
> Well, then you compile with -Os or equivalent, and hope the compiler
> does the right thing and optimizes for the size.
 
Sure, you use the right flags (and the right compiler). And you also
learn how to write code for such systems.
 
My point is that the size of the binaries can matter here.
 
> AFAIK there are even
> special compilers for embedded devices which can create smaller binaries.
 
Of course there are, especially for the very small devices (which are
rarely programmed in C++ anyway).
 
 
> In case of exception handling this means you trade some speed for the
> size. TANSTAAFL.
 
That is always the case with exception handling. Table-based exception
implementations are designed to minimise the impact for normal runs, at
the cost of speed or size for dealing with exceptions. Usually that's a
good tradeoff. (In embedded systems, you often disable exceptions
entirely.)
 
 
> When you do compile without -Os then it means you do not care about the
> size.
 
No, it certainly does not. It merely means that you are making a choice
other than having the compiler use size as the dominant factor in the
compilation. -O2 compilation can sometimes be smaller, and is often a
much more appropriate balance between size and speed (I'm assuming gcc
here). In particular, regardless of the flags you use you may make
design decisions aimed at smaller code space or at greater speed (or
flexibility, or other criteria).
 
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 20 12:23AM +0200

This can cause an exception or possibly just a crash or UB, in Windows:
 
std::locale{ setlocale( LC_ALL, nullptr ) }
 
Full example program:
 
 
-------------------------------------------------------------------------
#include <iostream>
#include <locale>
#include <locale.h>
#include <stdexcept>
#include <stdlib.h>
 
auto main()
-> int
{
setlocale( LC_ALL, "" ); // Default national locale (UTF-8 in *nix)
setlocale( LC_NUMERIC, "C" ); // Periods as fraction
separators, please.
 
std::cout << "C level locale = \"" << setlocale( LC_ALL, nullptr )
<< "\"\n";
 
try
{
const auto& loc = std::locale{ setlocale( LC_ALL, nullptr ) };
std::cout << "C++ level locale = " << loc.name() << "\n";
return EXIT_SUCCESS;
}
catch( std::exception const& x )
{
std::cerr << "!" << x.what() << "\n";
}
catch( ... )
{
std::cerr << "!!! non-standard exception\n";
}
return EXIT_FAILURE;
}
-------------------------------------------------------------------------
 
 
Results with respectively Visual C++ and MinGW g++, in that order:
 
 
-------------------------------------------------------------------------
[P:\temp]
> cl locale-sabotage.cpp /Feb
locale-sabotage.cpp
 
[P:\temp]
> b
C level locale = "LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan
Mayen.1252"
C++ level locale = LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan Mayen.1252
 
[P:\temp]
> g++ locale-sabotage.cpp
 
[P:\temp]
> a
C level locale = "LC_COLLATE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_CTYPE=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_MONETARY=Norwegian Bokmål_Svalbard and Jan
Mayen.1252;LC_NUMERIC=C;LC_TIME=Norwegian Bokmål_Svalbard and Jan
Mayen.1252"
!locale::facet::_S_create_c_locale name not valid
-------------------------------------------------------------------------
 
 
This is in Windows 10. I seem to remember that locale names were like
"no_NB.1252", and not the long descriptive text above. Has something
changed?
 
Because I also remember g++'s C++ level locale handling to be missing or
screwed up, so that /could/ be the problem?
 
 
Cheers!,
 
- Alf
Vir Campestris <vir.campestris@invalid.invalid>: Jul 19 09:55PM +0100

On 18/07/2018 06:06, Chris M. Thomasson wrote:
 
> I have indented them all before. It does seem to have potential scaling
> issues wrt deeply nested namespaces.
 
You are Linus and ICMFP.
 
The Linux Kernel standards have an implied limit on nesting by making
sure that all tabs are 8, and the code must fit on a VT52.
 
Nowadays we have bigger screens. Nesting deeply is not the issue it used
to be. I have one of the narrowest screens on the department - 1200
pixels (1) - and that doesn't seem to be narrow enough that nesting is a
a limit. It's print statements where I need to wrap.
 
Andy
--
2x1920x1200 in portrait mode :)
Thiago Adams <thiago.adams@gmail.com>: Jul 19 02:12PM -0700

On Tuesday, July 17, 2018 at 6:00:07 PM UTC-3, Adam Wysocki wrote:
> Hi,
 
> What is your preference towards indenting contents of namespaces?
 
My preference is not to use namespaces.
 
Unless I have to do some library for other people
(other companies) to use. In this case I will have just
one level like namespace MyLib;
In this case I would use the indentation that the IDE does
by default.
 
The reason to avoid namespaces is that I don't want to
add more text and logic (like the reasoning about
the namespace names) to the code to solve one
problem (name crash) that I don't have and from my
experience I will never had or it will be just
one function that could(should) be static.
 
Also I don't want o manage "sets" of better logic for
the position of some function and creates a debate
about this.
 
If the code looks like many layers of abstraction
and the layers are represented by namespace this is
a bad sign for me. Just like class hierarchies.
 
Generally I use folders to represent source
that will always be used together because they depend on
each other to build and they can be reused in other
projects just coping the folder.
"Chris M. Thomasson" <invalid_chris_thomasson@invalid.invalid>: Jul 19 02:30PM -0700

On 7/17/2018 11:34 PM, Ian Collins wrote:
>> issues wrt deeply nested namespaces.
> Mitigate by sticking to two space indentation, or use nested namespace
> as Flibble showed.
 
Fwiw, I remember back in the day using something like:
______________________
namespace foo {
namespace bar {
namespace baz {
 
struct hello_there
{
int a;
};
 
}}} // foo::bar::baz
______________________
 
Love the new syntax wrt:
______________________
 
namespace foo::bar::baz
{
struct hello_there
{
int a;
};
}
______________________
 
Nice. :^)
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: Jul 19 10:36PM +0100

On 19/07/2018 22:12, Thiago Adams wrote:
> that will always be used together because they depend on
> each other to build and they can be reused in other
> projects just coping the folder.
 
Is this a deliberate troll? I sincerely hope so as the alternative is too
depressing to think about.
 
/Flibble
 
--
"Suppose it's all true, and you walk up to the pearly gates, and are
confronted by God," Bryne asked on his show The Meaning of Life. "What
will Stephen Fry say to him, her, or it?"
"I'd say, bone cancer in children? What's that about?" Fry replied.
"How dare you? How dare you create a world to which there is such misery
that is not our fault. It's not right, it's utterly, utterly evil."
"Why should I respect a capricious, mean-minded, stupid God who creates a
world that is so full of injustice and pain. That's what I would say."
Manfred <noname@add.invalid>: Jul 19 09:15PM +0200

On 7/19/2018 7:58 PM, Bart wrote:
>> this and that. Every time.
 
>> That isn't how modern optimizing compilers work.
 
> But they /might/ do all that?
 
In the case of std::unique_ptr (and in other cases, but let's stick to
the case at hand) they don't do all that :
The size of a unique_ptr is the same as that of a raw pointer, and the
constructor and destructor are inline templates that resolve to setting
the internal pointer and calling delete, so in general there is no
runtime overhead in using std::unique_ptr.
There may be some overhead if the unique_ptr is /moved/ around, which
means that the internal pointer is moved from unique_ptr to unique_ptr,
and this involves calling some extra inline constructors and destructors
(unless they are optimized away), which may do nothing except
setting/testing for null on the internal pointer.
 
 
> Or if they don't, they might be expending effort in assembling all those
> operations, and then expend more effort in figuring out how to get rid
> of them again. And then people complain about build times.
 
There can be some compile-time overhead, which is usually well accepted
given the advantage in code robustness.
Bart <bc@freeuk.com>: Jul 19 06:58PM +0100

On 19/07/2018 18:46, bitrex wrote:
> may do nothing at all), making stack allocations, assigning-immediate
> class member variables, running all around doing this and that. Every time.
 
> That isn't how modern optimizing compilers work.
 
But they /might/ do all that?
 
Or if they don't, they might be expending effort in assembling all those
operations, and then expend more effort in figuring out how to get rid
of them again. And then people complain about build times.
 
--
bart
Thiago Adams <thiago.adams@gmail.com>: Jul 19 11:53AM -0700

On Thursday, July 19, 2018 at 3:19:18 PM UTC-3, Bo Persson wrote:
> 00007FF7893D101F add rsp,28h
> 00007FF7893D1023 ret
 
> What destructor call do you want to remove?
 
I don't want to call the destructor of the moved
object. (p1)
 
MSVC also removed the p1 going to zero after move.
 
I think this optimization is for inline code like this:
 
 
{
int * p1 = new int();
int *p2;
p2 = p1;
p1 = 0; //<--- goes to 0
delete p2;
if (p1 != 0) //compiler knows that p1 is always zero
{
//removed
delete p1;
}
}
 
I will try something not inline just to see what happens.
Thiago Adams <thiago.adams@gmail.com>: Jul 19 12:12PM -0700

On Thursday, July 19, 2018 at 3:53:31 PM UTC-3, Thiago Adams wrote:
...
> I will try something not inline just to see what happens.
 
I created an object similar of unique_ptr but not template
and not inline (the source was in a separated cpp file)
and the compiler did the optimization as well.
 
 
 
Then I added an printf to the destructor and the compiler
did the optimization as well, leaving just the printf
and removing the if and delete.
 
IntUniquePtr::~IntUniquePtr()
{
printf("a");
if (p)
delete p;
}
 
 
So the optimization was like inline code. Maybe VC++ is
doing inline even when we didn't put the implementation
together with the class declaration - this is my guess.
gof@somewhere.invalid (Adam Wysocki): Jul 19 07:17PM

> p2 = std::move(p1);
 
> in this case, the compiler would be allowed to remove
> the destructor call of the p2.
 
It does so.
 
Consider this code:
 
#v+
#include <memory>
#include <iostream>
 
class C
{
public:
C() { std::cout << "ctor" << std::endl; }
~C() { std::cout << "dtor" << std::endl; }
};
 
int main()
{
std::unique_ptr<C> c1(std::make_unique<C>());
std::cout << "between" << std::endl;
std::unique_ptr<C> c2(std::move(c1));
}
#v-
 
I compiled it with g++ 6.3.0 (with -std=c++14) and it produced:
 
#v+
ctor
between
dtor
#v-
 
--
[ Adam Wysocki :: Warsaw, Poland ]
[ Email: a@b a=grp b=chmurka.net ]
[ Web: http://www.chmurka.net/ ]
Manfred <noname@add.invalid>: Jul 19 09:23PM +0200

On 7/19/2018 9:17 PM, Adam Wysocki wrote:
> between
> dtor
> #v-
 
This does not take into account the constructors (specifically the move
constructor) and destructor of the unique_ptr, only those of C.
Thiago Adams <thiago.adams@gmail.com>: Jul 19 12:26PM -0700

On Thursday, July 19, 2018 at 4:17:50 PM UTC-3, Adam Wysocki wrote:
> between
> dtor
> #v-
 
In this case, the dtor of C will not be printed twice
even in debug because the pointer is null.
the print must be at the unique_ptr object.
Thiago Adams <thiago.adams@gmail.com>: Jul 19 01:32PM -0700

On Thursday, July 19, 2018 at 4:12:56 PM UTC-3, Thiago Adams wrote:
...
 
> So the optimization was like inline code. Maybe VC++ is
> doing inline even when we didn't put the implementation
> together with the class declaration - this is my guess.
 
Just for curiosity:
This code in C also removes the second call to free.
 
int main()
{
struct X * p1 = malloc(sizeof * p1);
struct X * p2;
p2 = p1;
p2 = 0;
 
X_Delete(p1);
X_Delete(p2);
 
return 0;
}
 
void X_Delete(struct X* pX)
{
if (pX) {
free(pX);
}
}
 
 
But in case I remove the "if"
 
if (pX) {
free(pX);
}
 
and leave just
 
free(pX);
 
then the free is called twice.
 
The optimizer follow the state of p2 and removes
everything inside the if.
Thiago Adams <thiago.adams@gmail.com>: Jul 19 01:43PM -0700

On Thursday, July 19, 2018 at 5:33:02 PM UTC-3, Thiago Adams wrote:
 
> then the free is called twice.
 
> The optimizer follow the state of p2 and removes
> everything inside the if.
 
One difference from optimizations and "Destructor elision" is that
even when the destructor has some code, let's say a log, or printf,
the compiler is not required to call this destructor.
(similar of copy elision)
Vir Campestris <vir.campestris@invalid.invalid>: Jul 19 09:27PM +0100

On 19/07/2018 15:21, Scott Lurndal wrote:
>> automated refactoring implemented in elisp, but nope. They have
>> essentially the same environment I had in 1988.
 
> If it works for them, why should they change?
 
30 years ago I was writing C. C worked for me, why should I change?
 
Andy
Ian Collins <ian-news@hotmail.com>: Jul 20 08:32AM +1200

On 20/07/18 08:27, Vir Campestris wrote:
>>> essentially the same environment I had in 1988.
 
>> If it works for them, why should they change?
 
> 30 years ago I was writing C. C worked for me, why should I change?
 
30 years ago I had a 13" CRT. C worked for me, why should I change?
 
--
Ian
Vir Campestris <vir.campestris@invalid.invalid>: Jul 19 09:24PM +0100

On 17/07/2018 23:40, Paavo Helde wrote:
> leaks or just failing to call a special function for it
> (scalable_allocation_command(TBBMALLOC_CLEAN_ALL_BUFFERS, NULL) for TBB,
> for example).
 
I've fixed bugs in that area by setting custom deleters in
(unique|shared)_ptr.
 
Andy
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: