Tuesday, July 16, 2019

Digest for comp.lang.c++@googlegroups.com - 22 updates in 3 topics

Vir Campestris <vir.campestris@invalid.invalid>: Jul 16 09:43PM +0100

On 10/07/2019 17:51, Richard wrote:
> is dominant in the embedded space and not much manages to displace it
> except for CPU specific assembly language and even there, most people
> only use assembly for small sections of the overall system.
 
We're mostly C++, with a smattering of C, especially in 3rd party
libraries. And while I may be an old fart there are several
20-somethings full time, plus a couple of interns for the summer from
the local uni.
 
Andy
Ian Collins <ian-news@hotmail.com>: Jul 17 09:02AM +1200

On 17/07/2019 08:43, Vir Campestris wrote:
> libraries. And while I may be an old fart there are several
> 20-somethings full time, plus a couple of interns for the summer from
> the local uni.
 
Same (in all aspects!) here. C and C++ are very much alive in the
embedded space. We have 60+ on our C++ team and down the road there's
another company with a similar sized C team.
 
--
Ian.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jul 15 09:12PM -0400

On 7/15/19 7:18 PM, Soviet_Mario wrote:
> On 16/07/19 00:40, Öö Tiib wrote:
>> On Tuesday, 16 July 2019 01:01:03 UTC+3, Soviet_Mario wrote:
...
>> constructors or destructors. 2) Returning objects of class type
>> results with RVO (no copies made).
 
> could you explain this acronym ?
 
"... the return statement initializes the glvalue result or prvalue
result object of the (explicit or implicit) function call by
copy-initialization (11.6) from the operand. [ Note: A return statement
can involve an invocation of a constructor to perform a copy or move of
the operand if it is not a prvalue or if its type differs from the return
type of the function. A copy operation associated with a return
statement may be elided or converted to a move operation if an automatic
storage duration variable is returned." (9.6.3p2)
 
RVO is abbreviation for "Return Value Optimization", and refers to cases
in which a call to a copy constructor could in principle occur, but may
be elided.
 
That clause uses a couple of terms that you might not be familiar with:
 
"A glvalue is an expression whose evaluation determines the identity of
an object, bit-field, or function.
A prvalue is an expression whose evaluation initializes an object or a
bit-field, or computes the value of the operand of an operator, as
specified by the context in which it appears." (6.10p1).
 
> automatic from "automatic" variables (with local scope, built on the
> stack) contrasted with "dynamic" variables (allocated manually from
> the heap and whose lifetime is to be manually managed too).
 
The standard term that matches what you mean is "non-static data member"
(12.2p3). Note that the storage duration of a non-static data member is
always the same as the storage duration of the containing object
(6.7.5p1). Non-static data members can therefore have static, automatic,
dynamic, or thread storage duration.
 
 
> you are right, I mis-used the term ! I just meant some object
> containing both some automatic members and also some dynamically
> allocated ones. TY
 
A member is not dynamically allocated unless it is a non-static data
member of a dynamically allocated object, in which case all non-static
data members of the same object are dynamically allocated.
 
I suspect that what you mean is members that are pointers to dynamically
allocated memory. Pointers are not distinguished by the storage duration
of the objects that they point at, any pointer can point at any suitable
object, regardless of that object's storage duration. Therefore, it's
not appropriate for the compiler to automatically free the memory a
pointer points at. It is the responsibility of the programmer, to make
sure that the memory it points at is in fact deallocated, when
appropriate, and only if it was dynamically allocated. That's one of the
things that user-defined destructors are used for - to make sure the
memory is deallocated.
 
Smart pointers are specialized classes that have destructors that, in
some cases, automatically deallocate the memory that they contain a
pointer to.
"Öö Tiib" <ootiib@hot.ee>: Jul 15 08:22PM -0700

On Tuesday, 16 July 2019 02:18:51 UTC+3, Soviet_Mario wrote:
 
> > constructors or destructors. 2) Returning objects of class
> > type results with RVO (no copies made).
 
> could you explain this acronym ?
 
I see James Kuyper made decent effort to explain it.
In practice the implementations pass the address for
return value of class type to function like other arguments.
The function is allowed to construct the object that it is going
to return at that address and so elide copying when returning.
It often surprises people who wrote side effects to copy or
move constructors or destructors.
 
> local scope, built on the stack) contrasted with "dynamic"
> variables (allocated manually from the heap and whose
> lifetime is to be manually managed too).
 
Hmm.
 
Making efficient manual management of resources with C++
has become quite complicated topic.
It can take more than week to read and to understand the
nuances of "RAII", "rule of three", "copy-swap idiom",
"rule of five", "rule of zero" and "rule of four (and half)".
 
People who write about one of those tend to oversimplify the issue.
For example they typically forget to tell that with dynamically
polymorphic class hierarchy (with virtual functions) all exposed
copying, moving or swapping may cause sliced objects or worse.
So protect or =delete all that and use factories and cloning
with such hierarchies instead.
Paavo Helde <myfirstname@osa.pri.ee>: Jul 16 03:04PM +0300

On 16.07.2019 1:00, Soviet_Mario wrote:
> but then the said former function invokes some class methods that DO
> some dynamic allocation, and then the function returns passing outside a
> copy by-value of the built object to the caller, placed "partially" on
 
Your question is not very clear, consider to add some code examples to
make it clearer.
 
In general, defining classes which do their own own low-level dynamic
memory allocation is tricky. One typically needs to define custom
constructors, assignments and destructors.
 
Fortunately enough, there is near zero need to do such low-level dynamic
allocation nowadays in C++, as it's properly done and encapsulated in
standard library classes like std::vector. If some objects really need
to be dynamically allocated, like some OOP hierarchy objects, one should
use std::make_unique() (or maybe std::make_shared() in special
circumstances) and appropriate smartpointers.
 
That said, the answer to your question is probably that by default the
copies in C++ are "shallow" (a copy of a pointer or a standard
smartpointer is just another pointer with the same value), to make it
deep one needs to define custom copy and assignment operations. The
latter is done e.g. by std::vector, so copying std::vector objects
always copies the whole data array.
 
hth
Paavo
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 16 02:28PM +0200

On 16/07/19 03:12, James Kuyper wrote:
> always the same as the storage duration of the containing object
> (6.7.5p1). Non-static data members can therefore have static, automatic,
> dynamic, or thread storage duration.
 
could you give me a reference of the manual you are
referring to with the notation "12.2p3" etc ?
I mean a reference to some online manual
 
 
> A member is not dynamically allocated unless it is a non-static data
> member of a dynamically allocated object, in which case all non-static
> data members of the same object are dynamically allocated.
 
I am referring to objects of a class derived from MyString,
that have some automatic and / or static data members,
existing even for "empty" MyStrings, and some dynamic
content (created and destroyed using new char [] / delege []
 
an empty MyString can be built without calling any new char
[] / delege [], but further elaboration, which assigns
content, requires it, or even reallocation.
 
So I was asking about the behaviour of returning data for
these objects whose memory "footprint" is hybrid and also
variable depending on context.
 
I need to understand of glvalue and grvalue, as I can only
recall the concepts of R-value and L-value, to one side, and
value-types vs reference-types on the other, but I surely
have to complete the definitions I understand
 
 
> I suspect that what you mean is members that are pointers to dynamically
> allocated memory.
 
exactly : some "rich" strings, that have a constant
framework of members and an "optional" content, on the HEAP,
pointed to by an automatic pointer member
 
> Pointers are not distinguished by the storage duration
 
yes I know pointers are not, but I have doubts for the
actual content pointed to.
 
Avoiding DEEP copying (just copying the pointer, and thus
having more than one pointer targeting the same content,
would be destructive, as each MyString must have is private
and locale space reserved, and modifying it must not affect
others)
 
> of the objects that they point at, any pointer can point at any suitable
> object, regardless of that object's storage duration.
 
ok, but my doubt was about : is it dynamic memory
automatically duplicated (skeptic) ? Is NEVER duplicated ?
(harmful). Is the whole regulated by invoking the
COPY-constructor, so that it can decide ?
 
> Therefore, it's
> not appropriate for the compiler to automatically free the memory a
> pointer points at.
 
yes, but my doubt was more limited, I try to repeat it.
 
In the CALLEE, building a return value (passed not by
address or reference, just by-value => an hint to copy
data), some dynamic allocation is done explicitly.
The copy received by the caller, then would ...
1) receive NO data at all (I'm not saying the compiler has
ever freed it, simply it remains lost, inaccessible,
resultin in a leak)
2) receive a link to the same content, copied in another pointer
3) receive a copy of the dynamic data placed elsewhere
(which seems not reasonable if it was up to the compiler to
reallocate some room, transfer the data, deallocate the
CALLEE copy, but maybe this would be done if a COPY
constructor is delegated, and this always makes a copy ...
well this scenario seems heavy and inefficient, it would be
good to just copy automatic members so that just one
reference to data would exist after return, the one of the
caller)
 
> It is the responsibility of the programmer, to make
> sure that the memory it points at is in fact deallocated, when
> appropriate,
 
and this is managed now overloading operator = and also in
the copy constructor.
It would be safe but inefficient to have this same code when
returning objects by value that were just built (in the case
of initialization it would be inevitable instead, as there
is no such duplicated operation)
 
 
> Smart pointers are specialized classes that have destructors that, in
> some cases, automatically deallocate the memory that they contain a
> pointer to.
 
I don't master them at all .... by now I prefer to just
resort to things I understand well.
And C++ has changed very very much in 10-15 years I had
almost abandoned it :\
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 16 02:37PM +0200

On 16/07/19 05:22, Öö Tiib wrote:
>>> type results with RVO (no copies made).
 
>> could you explain this acronym ?
 
> I see James Kuyper made decent effort to explain it.
 
sure, he was kind. I just have to collect a copy of the
document he was referring to
 
> In practice the implementations pass the address for
> return value of class type to function like other arguments.
 
do you mean the CALLER passes an "hidden" further parameter
to the CALLEE indicating where to place the (automatic part
of the) built object ?
In this case, the inefficient COPY-constructor would not be
invoked ...
 
> The function is allowed to construct the object that it is going
> to return at that address and so elide copying when returning.
 
intresting ... I knew nothing about this mechanism
 
> It often surprises people who wrote side effects to copy or
> move constructors or destructors.
 
I could not understand what you meant ...
I had to add the copy constructor to just clone-initialize
objects explicitly.
I thought (wrongly) it would have been invoked also in
returning objects on the stack. But if this does not happen,
much better !
 
 
> Hmm.
 
> Making efficient manual management of resources with C++
> has become quite complicated topic.
 
I was afraid so, but I have to do some MyString class, and
there the dynamic management is unavoidable I fear
 
> It can take more than week to read and to understand the
> nuances of "RAII", "rule of three", "copy-swap idiom",
> "rule of five", "rule of zero" and "rule of four (and half)".
 
I had just read about resource acquisition is
initialization. Never heard of the other bibl.
 
> copying, moving or swapping may cause sliced objects or worse.
> So protect or =delete all that and use factories and cloning
> with such hierarchies instead.
 
 
I am still not using virtual classes/members.
And not even inheritance of the kind IS-A (I tend to use the
HAS-A pattern, which I'm more confident of)
 
 
actually I'm using C++ more like "a better C" and little
more, or C-with-templates.
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 16 02:42PM +0200

On 16/07/19 14:04, Paavo Helde wrote:
> low-level dynamic allocation nowadays in C++, as it's
> properly done and encapsulated in standard library classes
> like std::vector.
 
It was my first attempt : std::vector and std::list, but I
was unable to find the methods to do both dynamic
reallocation (grow / shrink) with the former and also random
access BY INDEX with the latter.
 
> or a standard smartpointer is just another pointer with the
> same value), to make it deep one needs to define custom copy
> and assignment operations.
 
I have defined both, it seemed inevitable with read-write
Strings
 
> The latter is done e.g. by
> std::vector, so copying std::vector objects always copies
> the whole data array.
 
I'll rescan the std:: types you adviced though :\
TY
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
Paavo Helde <myfirstname@osa.pri.ee>: Jul 16 04:15PM +0300

On 16.07.2019 15:42, Soviet_Mario wrote:
 
> It was my first attempt : std::vector and std::list, but I was unable to
> find the methods to do both dynamic reallocation (grow / shrink) with
> the former and also random access BY INDEX with the latter.
 
std::vector is perfectly capable to dynamically grow and shrink. Insert
and erase elsewhere than in the end might be a bit slow if you have
millions of elements, but one should not worry about it prematurely.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jul 16 09:47AM -0400

On 7/16/19 8:28 AM, Soviet_Mario wrote:
>> On 7/15/19 7:18 PM, Soviet_Mario wrote:
>>> On 16/07/19 00:40, Öö Tiib wrote:
>>>> On Tuesday, 16 July 2019 01:01:03 UTC+3, Soviet_Mario wrote:
...
 
> could you give me a reference of the manual you are
> referring to with the notation "12.2p3" etc ?
> I mean a reference to some online manual
It's not a "manual", it's n4659.pdf, a free draft version of the C++
standard: the draft is almost exactly the same as the official C++2017
standard, so it's hard for me to justify paying the significant extra
cost of buying the actual standard. You can find it at
<http://www.open-std.org/jtc1/sc22/wg21/docs/standards>
 
...
>> data members of the same object are dynamically allocated.
 
> I am referring to objects of a class derived from MyString,
> that have some automatic and / or static data members,
 
Will you please stop using "automatic" for that purpose? The correct
term is "non-static". Given the following declarations, occurring inside
a function body:
 
MyString Automatic;
MyString *Dynamic = new MyString();
static MyString Static;
thread_local MyString ThreadLocal;
 
and assuming that MyString contains a non-static data member named
"data", then Automatic.data has automatic storage duration,
Dynamic->data has dynamic storage duration, Static.data has static
storage duration, and ThreadLocal.data has thread local storage
duration. Being "automatic" is NOT a characteristic of the "data"
member, only of it's containing object.
 
If that member is a pointer to dynamically allocated memory, then *data
has dynamic storage duration, regardless of what storage duration data
itself has.
 
...
> recall the concepts of R-value and L-value, to one side, and
> value-types vs reference-types on the other, but I surely
> have to complete the definitions I understand
 
glvalue and prvalue are refinements of the concepts of l-value and
r-value, respectively. Frankly, I haven't fully familiarized myself with
the details of that refinement.
 
...
>> object, regardless of that object's storage duration.
 
> ok, but my doubt was about : is it dynamic memory
> automatically duplicated (skeptic) ?
 
No.
 
> Is NEVER duplicated ?
 
It's duplicated whenever you explicitly write code duplicating it.
 
> (harmful). Is the whole regulated by invoking the
> COPY-constructor, so that it can decide ?
 
Only if you explicitly define the copy-constructor, and your
user-written copy constructor makes that decision.
 
For example, there is a strategy, called Copy-On-Write (COW), which
means that all direct copying, whether by assignment, construction, or
conversion, involves copying over only a pointer to the actual memory
being managed. As a result, a single block of memory might be shared
between many different containers. However, as soon as a write needs to
be done, the container in which the write occurred would copy the shared
memory to a new location, and then stop participating in the share. Only
then would it write to the new location.
 
That's all managed by user-written code - default constructors and
default assignment operator overloads never do anything that sophisticated.
 
I gather that COW used to be common in implementations of std::string,
but that it has since gone out of favor. My purpose in bringing it up is
only to point out that there are more sophisticated alternatives to your
simple shallow/deep copy distinction.
 
 
> 1) receive NO data at all (I'm not saying the compiler has
> ever freed it, simply it remains lost, inaccessible,
> resultin in a leak)
 
No.
 
> 2) receive a link to the same content, copied in another pointer
 
If the object contains a pointer to the content, then a default
constructor or a default assignment operator overload will simply copy
that pointer.
 
> 3) receive a copy of the dynamic data placed elsewhere
 
In order to get that behavior, you have to define your own non-default
constructors and non-default assignment operator overloads.
 
...
> returning objects by value that were just built (in the case
> of initialization it would be inevitable instead, as there
> is no such duplicated operation)
 
You misunderstand: returning objects by value is NOT a separate kind of
operation. It is performed by using constructors - a copy constructor is
sometime necessary; but constructing the return value directly in it's
final location is often a permitted optimization. What happens depends
entirely upon what you've defined those functions to do, or if you've
let them be defined by default, it depends upon what the default
versions do.
 
>> pointer to.
 
> I don't master them at all .... by now I prefer to just
> resort to things I understand well.
 
I recommend learning about smart pointers when you have time, but I also
agree that you should not use them until you've had time to learn about
them.
 
> And C++ has changed very very much in 10-15 years I had
> almost abandoned it :\
 
Among the most important changes that are relevant to this discussion is
"move" semantics. I'm not fully up to speed on move semantics, but my
understanding is that if you move one string into another string, only
the pointer to the contained data is copied, not the data itself, and
the original string ends up empty. The actual semantics of "move"
depends upon how you define move constructors or move assignment
operator overloads. As a general rule, if it is permissible to leave the
source empty, doing a move rather than a copy is usually more efficient,
and seldom less efficient.
James Kuyper <jameskuyper@alumni.caltech.edu>: Jul 16 10:07AM -0400

On 7/16/19 8:42 AM, Soviet_Mario wrote:
...
> It was my first attempt : std::vector and std::list, but I
> was unable to find the methods to do both dynamic
> reallocation (grow / shrink)
 
The relevant methods are various overloads to insert() and erase(), as
well as push_back() and pop_back(). If you simply want to expand the
allocated memory without filling it immediately, use reserve(). If you
want to shed unneeded allocated memory, use shrink_to_fit().
 
> with the former and also random
> access BY INDEX with the latter.
 
By it's vary nature std::list cannot support random access. If you need
random access, you shouldn't be using a list.
 
If you absolutely need use an index, std::next(list.begin(), n) will
return an iterator referring to the n'th element of the list. This isn't
true random access: it applies operator++() to the iterator n times, in
order to get to that location.
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 16 05:16PM +0200

On 16/07/19 15:47, James Kuyper wrote:
> standard, so it's hard for me to justify paying the significant extra
> cost of buying the actual standard. You can find it at
> <http://www.open-std.org/jtc1/sc22/wg21/docs/standards>
 
Thanks, I'm gonna get the DOC !
 
>> that have some automatic and / or static data members,
 
> Will you please stop using "automatic" for that purpose? The correct
> term is "non-static".
 
mmm, the fact is : to me non-static seems a WIDER definition
than automatic, as dynamic also is non-static :)
 
> storage duration, and ThreadLocal.data has thread local storage
> duration. Being "automatic" is NOT a characteristic of the "data"
> member, only of it's containing object.
 
uhm .... :\
 
 
> If that member is a pointer to dynamically allocated memory, then *data
> has dynamic storage duration, regardless of what storage duration data
> itself has.
 
this IS clear !
 
 
> glvalue and prvalue are refinements of the concepts of l-value and
> r-value, respectively. Frankly, I haven't fully familiarized myself with
> the details of that refinement.
 
OK ... no problem, maybe I won't need to refine too :)
 
 
> No.
 
>> Is NEVER duplicated ?
 
> It's duplicated whenever you explicitly write code duplicating it.
 
OK : I have written the copy-constructor, yes
 
 
> Only if you explicitly define the copy-constructor, and your
> user-written copy constructor makes that decision.
 
> For example, there is a strategy, called Copy-On-Write (COW), which
 
yes...no ! No, I don't want COW even if it is faster and
maybe more parsimonious. I just need code safer and simpler
to read.
 
> conversion, involves copying over only a pointer to the actual memory
> being managed. As a result, a single block of memory might be shared
> between many different containers.
 
yes it's like the SNAPSHOTS on virtual machine disks : they
actually record only the changes of status, not the entire
status of the file system. Also BTRFS snapshots work like that.
 
I'd prefer more "synced" status of each object than deferred
writes
 
> but that it has since gone out of favor. My purpose in bringing it up is
> only to point out that there are more sophisticated alternatives to your
> simple shallow/deep copy distinction.
 
agreed. I had not even thought about such more advanced
features as I just need to have simple and solid code : it
won't be performance intensive
 
 
>> 3) receive a copy of the dynamic data placed elsewhere
 
> In order to get that behavior, you have to define your own non-default
> constructors and non-default assignment operator overloads.
 
OK clear: I should not expect strange hidden behaviour.
 
I'm getting maybe close to some compilable code .... then
I'll inspect all in the Debugger. Some times is more useful
to observe live than to try to figure out theoretically
 
> operator overloads. As a general rule, if it is permissible to leave the
> source empty, doing a move rather than a copy is usually more efficient,
> and seldom less efficient.
 
mmm ... unheard of .... thanks for the hint !
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
James Kuyper <jameskuyper@alumni.caltech.edu>: Jul 16 10:30AM -0700

On Tuesday, July 16, 2019 at 11:16:57 AM UTC-4, Soviet_Mario wrote:
> On 16/07/19 15:47, James Kuyper wrote:
> > On 7/16/19 8:28 AM, Soviet_Mario wrote:
...
> > term is "non-static".
 
> mmm, the fact is : to me non-static seems a WIDER definition
> than automatic, as dynamic also is non-static :)
 
Yes, it is wider. All members are either member functions, static data
members, non-static data members, nested classes, or typedef members.
 
The problem is that "automatic", as that term is defined by the
standard, doesn't describe a property of a class member - it describes a
property of a particular instance of a class, and that property applies
to all of the non-static data members of that instance. It's not
meaningful to talk about some of the members being automatic and others
being dynamic.
 
This isn't just pedantry - it's directly relevant to the issue you're
worrying about. Consider a class containing just two members: a pointer
to a dynamically allocated array and a count of the number of elements
in that array. I suspect that you would describe the count as
"automatic"; I'm not sure exactly what you would say about the pointer.
The relevant facts are that both the count and the pointer are
non-static data members. They both always have the same storage duration
- which is the storage duration of the object that they are part of. The
memory that the pointer points at is dynamically allocated - but that's
not a feature of the pointer member, it's a feature of the way that the
class code uses that pointer.
 
A default copy will copy both the value of the count and the value of
the pointer, and will not do anything special regarding the memory that
the pointer points at. If that's not what you want to have happen,
you'll have to write a constructor that actually does do what you want
to have happen.
Soviet_Mario <SovietMario@CCCP.MIR>: Jul 16 07:44PM +0200

On 16/07/19 19:30, James Kuyper wrote:
> meaningful to talk about some of the members being automatic and others
> being dynamic.
 
> This isn't just pedantry -
 
oh, friend, never said or even thought so !!
I am just old-fashioned minded, an era when autopointers or
worse AUTO determination of the return value by its context
was really far fetched. So I was just trying to justify
myself, my way of thinking.
 
> to a dynamically allocated array and a count of the number of elements
> in that array. I suspect that you would describe the count as
> "automatic";
 
both the members are automatic. The pointer also IS. The
buffer pointed to, on the contrary, I would not call it
automatic, but dynamic.
 
> I'm not sure exactly what you would say about the pointer.
 
that in itself is automatic, as it still exist (it takes up
4 or 8 byte even if it contains NULLPTR)
 
> The relevant facts are that both the count and the pointer are
> non-static data members. They both always have the same storage duration
 
I agree in fact
 
> - which is the storage duration of the object that they are part of. The
> memory that the pointer points at is dynamically allocated - but that's
> not a feature of the pointer member,
 
yes it's not an intrinsical property of it, but this is not
really important for the passing out mechanism
 
> it's a feature of the way that the
> class code uses that pointer.
 
yes, now I have understood that I can rely on the fact that
the compiler itself generates no hidden code having side
effects on dynamic data, except for calling copy-constructor
and destructor, which I have to write myself.
 
And also that I cannot make assumptions whether or not the
copy constructor is actually called or some optimization
(like building the returned object in a location provided by
the CALLER itself, or copying it back by MY copy-ctor)
eliding copy happens.
 
 
> A default copy will copy both the value of the count and the value of
> the pointer, and will not do anything special regarding the memory that
> the pointer points at.
 
I have my hand written copy-ctor that copies data, so I
should be sure no overlapping ownership could take place
 
> If that's not what you want to have happen,
> you'll have to write a constructor that actually does do what you want
> to have happen.
 
yes. Many thanks to you and every one else. Some rust
removed successfully :) :)
CIAO
 
 
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
"Öö Tiib" <ootiib@hot.ee>: Jul 15 06:31PM -0700

On Tuesday, 16 July 2019 01:03:53 UTC+3, Ben Bacarisse wrote:
 
> Don't people learn the syntax of the languages they use anymore? (I'm
> joking, of course they don't, but C and C++ were designed in era when
> they did.)
 
It takes years to learn nuances of all C++ syntax. That syntax goes
back to times when count of punch cards used was concern on one
hand but it also receives substantial extensions after every few
years on the other hand.
 
struct obf {long ndx, *dun()&&, &gen(), mum() const, dat[42];};

Everybody use only subset of that syntax and everybody
agree that constraining it way more than the language requires
is very helpful. The only issue is that we sometimes want to
constrain it bit differently than others. From conflicting custom
constraints the white space is most trivial to solve.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Jul 16 03:04AM +0100

>> joking, of course they don't, but C and C++ were designed in era when
>> they did.)
 
> It takes years to learn nuances of all C++ syntax.
 
Yup. I was talking about the broad-brush syntax. I don't know the
details even after decades, but it's a fundamental part of both C and
C++'s syntax that "decoration" around the name alters the name's
relation to the base type:
 
int i, function(), array[], *pointer;
 
> back to times when count of punch cards used was concern on one
> hand but it also receives substantial extensions after every few
> years on the other hand.
 
It goes back to those days, but I would be surprised if that was ever a
concern. C was created for Unix, and Unix installations rarely used
punched cards.
 
<cut>
--
Ben.
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 16 05:48AM +0200

On 16.07.2019 03:31, Öö Tiib wrote:
 
> Everybody use only subset of that syntax and everybody
> agree that constraining it way more than the language requires
> is very helpful.
 
No, as a general statement that's not my experience.
 
For example, especially Juha and Mr. Fibble in this group complain
strenuously about my sometimes use of `P_<Type>` rather than `Type*`,
even though the former is a more constrained and in itself a uniform
notation, that supports always prefix `const` uniform notation.
 
I think you meant that most everybody agrees that /adopting a
convention/ of a more constrained notation, instead of actually doing
what you wrote, "constraining it" (i.e. adding hard constraints, like
the `P_` notation and similar notations does). However, I generally
don't agree with the idea of using mere convention when it's possible
and practical to express something in the language and have it enforced
by the compiler. In the same way, I disagree with the common idea of
explaining via comments things that can be expressed in the code itself.
 
 
> The only issue is that we sometimes want to
> constrain it bit differently than others. From conflicting custom
> constraints the white space is most trivial to solve.
 
For use of the original C syntax the placement of whitespace, if any,
IMO signals and subtly pushes in the direction of a way of thinking.
 
That's not the case any more when a more constrained C++ level notation
is adopted.
 
Then whitespace is just a formatting issue, a personal preference
without any ties to how to think of the structure of a declaration,
because there's then only one single, well defined, clear structure.
 
 
Cheers!,
 
- Alf
David Brown <david.brown@hesbynett.no>: Jul 16 08:47AM +0200

On 16/07/2019 05:48, Alf P. Steinbach wrote:
> strenuously about my sometimes use of `P_<Type>` rather than `Type*`,
> even though the former is a more constrained and in itself a uniform
> notation, that supports always prefix `const` uniform notation.
 
There is a big difference between constraining the syntax, and adopting
a completely different syntax.
 
Constraining the syntax means rules like "only declare one identifier at
a time." That would mean you can avoid several common (but not all)
possible mixups and confusions with pointer declarations - since you can
no longer write "int* a, b;", no one can wonder if you meant "b" to be a
pointer also.
 
What you are doing with your "P_<Type>", and all your other macros and
your library, is changing the appearance and nature of the language.
Now, I can agree that for some purposes, there are advantages. And if
one were making a new programming language, a syntax like P_<Type> might
be chosen instead of "Type*". But this group is about C++, not AC++
written in Alf's own C++. It does not matter that the code is valid C++
(ignoring the dollar sign) and the library is available online.
 
What you write is akin to C programmers who start their code:
 
#define R return
#define G goto
#define I int
 
and then proceed to write their code in a way /they/ find clear but no
one else likes.
 
When you are writing your own code, and large scale projects where your
library and style might have advantages, it is fair enough - anyone
working on the code should be familiar with your system. When you are
posting to a newsgroup for a wide audience who are not familiar with
your library (some are barely familiar with C++), then it is important
to write as simply and clearly, and in as common and standard a manner,
as possible.
 
 
> convention/ of a more constrained notation, instead of actually doing
> what you wrote, "constraining it" (i.e. adding hard constraints, like
> the `P_` notation and similar notations does).
 
Your notation is not a constraint - not as other people understand the
word. Please be careful with the word "constraint" until you agree on
the meaning with other people - you'll just cause confusion, and cause
arguments where people actually agree.
 
> and practical to express something in the language and have it enforced
> by the compiler. In the same way, I disagree with the common idea of
> explaining via comments things that can be expressed in the code itself.
 
I think most will agree with that - but it is an entirely orthogonal
point, and no one has been suggesting otherwise.
 
"Alf P. Steinbach" <alf.p.steinbach+usenet@gmail.com>: Jul 16 11:52AM +0200

On 16.07.2019 08:47, David Brown wrote:
>> notation, that supports always prefix `const` uniform notation.
 
> There is a big difference between constraining the syntax, and adopting
> a completely different syntax.
 
Yes, that's literally correct, but the in-context implication that
`P_<Type>` is a different syntax is wrong.
 
It's still C++ syntax.
 
The compiler would not accept it if it were not.
 
Since it's a constrained use of C++ syntax you find it "completely
different" than purely C syntax, but that is at best a colored
associative perception.
 
That is, you /feel/ that limiting oneself to the C++ template syntax for
pointer declarations is "completely different", but as a technical
statement that's incorrect misleading bollocks.
 
Confusing that feeling with technical fact is a fallacy.
 
 
> possible mixups and confusions with pointer declarations - since you can
> no longer write "int* a, b;", no one can wonder if you meant "b" to be a
> pointer also.
 
Yes, that's one thing `P_<Type>` does.
 
But from context you're implying that it does not.
 
That's a second fallacy, the assertion of a plainly incorrect "fact".
 
 
> What you are doing with your "P_<Type>", and all your other macros and
> your library, is changing the appearance and nature of the language.
 
Yes, changing the /appearance/ to something simpler, is part of what one
does by systematically constraining one's use of features.
 
And that's what you've argued for yourself up-thread, still quoted in
this reply; "very helpful", you wrote about it.
 
So, with the interpretation that for `P_` you refer to the declaration
simplifications as negative, while earlier, for use of more brittle
by-convention constraints you referred to it as positive, you're
contradicting yourself, a third fallacy.
 
Since you contradict yourself you are apparently failing to see that
you're doing it.
 
One common reason for such blindness, a blind zone regarding one's
self-contradictions about something, is that one is writing in a haze of
vision-defeating emotion.
 
 
> #define I int
 
> and then proceed to write their code in a way /they/ find clear but no
> one else likes.
 
This is a straw-man fallacious argument against use of the library I
sometimes choose to employ, a fourth fallacy.
 
Arguing against use of that library is itself a straw-man fallacious
argument against notation like `P_`. It's also a kind of fallacy called
a faulty or hasty generalization, two fallacies in one. But let's count
this as just one combined fifth fallacy.
 
The two fallacies above come on top of your three fallacies some
paragraphs earlier, i.e. five fallacies so far in just a few paragraphs,
which again indicates to me that you're writing in a haze of emotion — I
would presume with a main component that of belonging to a group — that
clouds and defeats your critical thinking.
 
 
> your library (some are barely familiar with C++), then it is important
> to write as simply and clearly, and in as common and standard a manner,
> as possible.
 
This is again incorrect in so many ways.
 
A main way that it's wrong: an argument against my use of a library is,
again, not valid as an argument against `P_` notation.
 
So, that single aspect of the wrongness is a sixth fallacy so far.
 
 
>> the `P_` notation and similar notations does).
 
> Your notation is not a constraint - not as other people understand the
> word.
 
Seventh fallacy.
 
 
 
>  Please be careful with the word "constraint" until you agree on
> the meaning with other people - you'll just cause confusion, and cause
> arguments where people actually agree.
 
Eight fallacies.
 
This is like some text out of a lunatic asylum, just all
self-contradictions and fallacies.
 
But I believe you'll find support in this group, because (I presume)
that's the main driver, the group membership.
 
With emotions, rational thinking doesn't really apply.
 
However, how you landed on perceiving the group's view as coincident
with the vitriol spewed out by Mr. Fibble, is beyond me.
 
 
>> can be expressed in the code itself.
 
> I think most will agree with that - but it is an entirely orthogonal
> point, and no one has been suggesting otherwise.
 
Ninth fallacy, in the denial area.
 
 
 
>> Then whitespace is just a formatting issue, a personal preference
>> without any ties to how to think of the structure of a declaration,
>> because there's then only one single, well defined, clear structure.
 
Cheers!,
 
- Alf
David Brown <david.brown@hesbynett.no>: Jul 16 12:45PM +0200

On 16/07/2019 11:52, Alf P. Steinbach wrote:
 
I'm snipping most of what you wrote - going through it point for point
would be, well, pointless.
 
> But I believe you'll find support in this group, because (I presume)
> that's the main driver, the group membership.
 
You will find that most people in the group ignore the code you post
when it contains your special language. The fact that it can be
compiled by a C++ compiler, assuming one goes to the bother of finding
and downloading your library, is irrelevant.
 
 
> With emotions, rational thinking doesn't really apply.
 
> However, how you landed on perceiving the group's view as coincident
> with the vitriol spewed out by Mr. Fibble, is beyond me.
 
I don't approve of the hate posts Mr. Flibble makes. That does not mean
he is wrong in saying that your code is regularly unhelpful at best, and
incomprehensible at worst. But I dislike the way he says it.
 
 
> Ninth fallacy, in the denial area.
 
And you wonder why people aren't always appreciative of your posts.
 
 
You are an experienced C++ developer, sitting on a lot of good advice
and suggestions. But you choose to make your code posts in an
unconstructive way - an arrogant "my code is better than the rest of the
world" way. You are not alone in this - there are other numpties who
insist on adding "::std::" to everything, or who post with a layout and
spacing style that is, to be diplomatic, "unique".
 
You should learn that the way to communicate is by using a /common/
language - not what you personally believe to be the "best" language.
If that means posting code in a style that you consider sub-par, then
that is what you do.
 
Of course you can then have your own threads extolling the virtues of
your methods - they are interesting in their own rights, just not
usually as answers to other people's queries.
 
 
 
"Öö Tiib" <ootiib@hot.ee>: Jul 16 05:59AM -0700

On Tuesday, 16 July 2019 05:04:13 UTC+3, Ben Bacarisse wrote:
> C++'s syntax that "decoration" around the name alters the name's
> relation to the base type:
 
> int i, function(), array[], *pointer;
 
I understand the translation logic of syntax, but I also understand
that it is not what most programmers see intuitive to read. Major C++
compilers have lot of code for producing better diagnostics
about errors in declarations and even warn about potential illusions
(like vexing parse) but programmers are still frequently confused.
Other C-like languages have constrained and often also rearranged the
syntax of declaration and initialization of C.
 
 
> It goes back to those days, but I would be surprised if that was ever a
> concern. C was created for Unix, and Unix installations rarely used
> punched cards.
 
Good catch! It was not the most important concern of course.
I can't find any papers by Ken Thompson depicting it but Dennis
Ritchie describes it in detail. By him the major concern it solved
was memory used by compiler.
 
"The BCPL compiler readily handled such constructs by storing and
analyzing a parsed representation of the entire program in memory
before producing output. Storage limitations on the B compiler
demanded a one-pass technique in which output was generated as soon
as possible, and the syntactic redesign that made this possible was
carried forward into C."
http://www.bell-labs.com/usr/dmr/www/chist.html
 
Still my point remains, these concerns have long gone by now.
"Öö Tiib" <ootiib@hot.ee>: Jul 16 07:36AM -0700

On Tuesday, 16 July 2019 06:48:49 UTC+3, Alf P. Steinbach wrote:
> strenuously about my sometimes use of `P_<Type>` rather than `Type*`,
> even though the former is a more constrained and in itself a uniform
> notation, that supports always prefix `const` uniform notation.
 
Yes, I was saying that everybody agree that constraining is important
but disagree in how to constrain it. Within a team of project it is
solved either by dictatorship of lead developers or by democratic vote
of team members. Reaching agreements more globally is backbreaking if
not impossible.
 
> and practical to express something in the language and have it enforced
> by the compiler. In the same way, I disagree with the common idea of
> explaining via comments things that can be expressed in the code itself.
 
I did not mean only coding conventions. Often also tools of checking,
tools of aiding refactoring and supporting libraries are made to ease
the process of constraining and living with the constraints.
For example that is Microsoft's implementation of library to support
coding guidelines of Stroustrup and Sutter:
https://github.com/Microsoft/GSL
It is obvious that the more of such real support there is the easier
it is to adopt.
 
 
> Then whitespace is just a formatting issue, a personal preference
> without any ties to how to think of the structure of a declaration,
> because there's then only one single, well defined, clear structure.
 
The issue that different people want to constrain it differently still
remains. Discussions of those differences tend to get ... not
too charming. ;)
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: