On Saturday, 13 October 2018 05:24:29 UTC+3, Alf P. Steinbach wrote:
> On 12.10.2018 21:09, Paul wrote:
> > The code below is from Hackerrank. It looks suspicious to me because
> > the memory is allocated with new but freed with free.
> >
> > Is it ok?
>
> For portable code it's just Undefined Behavior.
>
> However, what's formal UB can be useful defined behavior with a given
> implementation. It's often exploited by the (compiler-specific)
> implementation of the standard library, e.g. in the `offsetof` code.
Yes, but that standard library may change with next patch. Are there
any ways to detect in code that it did?
> But
> the ordinary programmer has to consider several levels of defined-ness:
>
> * Defined by the C++ standard.
> * Defined by a large number of compilers (e.g. `#pragma once`, or
> `__COUNTER__`), a /de facto/ standard. However don't use that term over
> on Stack Overflow. They're too lazy, or maybe arrogant, to look up
> things they don't know, and I note that the care that one must exercise
> there has been adopted over on cppreference, which doesn't talk about de
> facto standards.
> * Defined by the compiler, and documented.
> * Defined by the compiler, but not documented (e.g., that you've found
> code from the compiler vendor that relies on some specific behavior).
> * No source other than your own testing indicates that this thing works.
Major issue there is lack of standardized way to detect compile time
the implementation-defined, some-other-standard-defined, compiler-defined
or compiler-option-defined features. So portable (in practice) code is
often full of preprocessor slices and obscurely unreadable static_assert
conditions.
> Usually, in discussions about C++ portable code is assumed, and so only
> code that passes via the first and second points above is considered OK.
>
> But one's portability goals can be much more limited, and for example,
> but even though I recall one such situation this must be very very rare,
> one may have to pass a `new`-allocated thing to a C routine that will
> `free` whatever it gets, and for efficiency avoid an extra `malloc` +
> copying.
Hmm ... but anything that C library can use and free must be dynamically
allocated POD and so there had to be possibility to malloc or calloc
storage for it instead?
> Then one may decide to go with one of the two last points. But
> I think that should be documented: "NOTE: NOT USING STRDUP BECAUSE
> MEASUREMENTS SHOWED THAT WAS TOO SLOW, AND BORKA C++ NEW /IS/ MALLOC".
Willfully going with one of the last two when some other bullet
explicitly documented it as "undefined behavior" (as on current case)
is considered "black magic". It will be nuisance later when it leads
into one of several inconveniences and difficulties. Most typical
difficulties that manifest are:
* choice of other useful tools (and platforms for running those) is
limited
* portability to newer versions of compiler is harder
* certain very desirable compiler flags (like optimizations) break it
* further maintainability of module is harder
When such difficulties manifest then with 100% our own code it "just
sucks". With others we are guilty. Admit personal fallibility, agree
that it was programming defect and help to remove the difficulties.
Any argument can bring lost trust, reputation, contracts and fame as
the evil author of "cursed legacy". What must be the alleged benefits
that make it worth that? No one did monitor if the end users were
happy about it or not. ;)