Tuesday, May 26, 2020

Digest for comp.lang.c++@googlegroups.com - 13 updates in 4 topics

Juha Nieminen <nospam@thanks.invalid>: May 26 06:42AM

> start wandering the countryside looking for someone to argue with. But
> that's all that you will accomplish with that: a perfectly-executed
> copy/paste.
 
I don't understand your attitude. His remarks are completely valid.
operator->() has very specific semantic meaning in C++, and trying to make
it do something else is only going to cause problems. The only reason why
you would try to make it do something else is if you are writing some kind
of obfuscated C++ or something.
 
> The original question, that was axed
 
Indeed, it was axed. Conversation over.
Sam <sam@email-scan.com>: May 26 07:06AM -0400

Juha Nieminen writes:
 
> > that's all that you will accomplish with that: a perfectly-executed
> > copy/paste.
 
> I don't understand your attitude. His remarks are completely valid.
 
So are mine.
 
> operator->() has very specific semantic meaning in C++, and trying to make
> it do something else is only going to cause problems.
 
Pretty much everything that can be done in C++ can cause problems, in some
form or fashion.
 
> The only reason why
> you would try to make it do something else is if you are writing some kind
> of obfuscated C++ or something.
 
I don't think it's obfuscated at all that if you have a temporary,
dereferencing it also gets you a temporary. It's a very simple concept. Not
sure why some people can't wrap their brains around it.
 
And I even mentioned a laughably trivial example where this is useful, a
std::unique_ptr prvalue.
 
And I even pointed out something else: a simple experiment shows that you
can easily do this /already/ with operator*, even though, like its cousin,
it also has "very specific semantic meaning in C++". So, I hate to be the
bearer of bad news, but just because something has "very specific semantic
meaning in C++", in the grand scheme of nothing it means …well, you got me,
it means absolutely nothing.
 
By the way, did you hear that operator++ can take an optional int parameter?
 
> > The original question, that was axed
 
> Indeed, it was axed. Conversation over.
 
I wasn't conversing with you in the first place.
Manfred <noname@add.invalid>: May 26 01:52PM +0200

On 5/26/2020 1:06 PM, Sam wrote:
 
> I don't think it's obfuscated at all that if you have a temporary,
> dereferencing it also gets you a temporary. It's a very simple concept.
> Not sure why some people can't wrap their brains around it.
 
Probably because what you are trying to "dereference" here is an object
of pointer type (specifically the result of operator ->, which is
required to be of pointer type), and as such it is an object on its own.
In particular, if you have an object of pointer type that is a
temporary, the object pointed to is in general /not/ a temporary - in
fact it is most commonly not, unless you exercise some peculiar gymnastics.
 
 
> And I even mentioned a laughably trivial example where this is useful, a
> std::unique_ptr prvalue.
 
In this example, the object pointed to (owned) by the std::unique_ptr
prvalue is definitely not a temporary: it is allocated on the heap (aka
"free store") and its lifetime is managed by the std::unique_ptr object.
On the contrary, the lifetime if temporaries is managed by the language.
 
> to be the bearer of bad news, but just because something has "very
> specific semantic meaning in C++", in the grand scheme of nothing it
> means …well, you got me, it means absolutely nothing.
 
The key point, as Öö Tiib wrote, is that pointers and references are
very different things (even if references may be implemented as hidden
pointers in some cases) - the former is an object on its own, the latter
is not an object.
 
Rvalue qualifications apply to references only, not to pointers.
 
Sam <sam@email-scan.com>: May 26 08:42AM -0400

Manfred writes:
 
> prvalue is definitely not a temporary: it is allocated on the heap (aka
> "free store") and its lifetime is managed by the std::unique_ptr object. On
> the contrary, the lifetime if temporaries is managed by the language.
 
Except that when the real, authentic, 100% original formula, std::unique_ptr
temporary goes away, so does its referenced object. It will cease to exist.
It will be no more. It will join the choir invisible. It will become an ex-
object.
 
Because that's how it works, by definition. This is not a complicated
concept.
 
Ref-qualifiers on class methods exist precisely to crack that nut, to
provide different overloads when they're being called on an object that will
soon cease to exist, will be no more, join the choir invisible, and become
an ex-object; and thusly be able to do something sensible about it.
 
Except that they won't work here.
 
Again, they'll work just fine when invoked as (*ptr).method(), (if
appropriately overloaded) but not as ptr->method(). No way to make that work.
 
> in some cases) - the former is an object on its own, the latter is not an
> object.
 
> Rvalue qualifications apply to references only, not to pointers.
 
Except that everywhere one looks, a->b is always defined as "just like
(*a).b", but you can't overload it in this manner. Too bad.
 
After thinking about it, I can kind of see a way to make it happen, to have
an overloaded "operator->" hacked up so that a
reasonable facsimile of a unique_ptr's, ->func() end up selecting a different overload in
the referenced object. But it's too fugly:
 
class some_big_object { /* ... */ };
 
struct hidden_base {
 
some_big_object func()
{
return some_big_object();
}
 
virtual some_big_object rfunc()=0;
};
 
class real_object : public hidden_base {
 
some_big_object something;
 
public:
 
some_big_object &func() { return something; }
 
some_big_object rfunc() override { return something; }
};
 
Now, a custom smart pointer can have a normal "operator->()" overload that
returns a real_object* and a "operator->() &&" overload that returns a
pointer to the hidden_base. Quite fugly, but it'll work.
Manfred <noname@add.invalid>: May 26 05:06PM +0200

On 5/26/2020 2:42 PM, Sam wrote:
> std::unique_ptr temporary goes away, so does its referenced object. It
> will cease to exist. It will be no more. It will join the choir
> invisible. It will become an ex-object.
 
Yes, it will be delete'd. Still, technically it is not a temporary.
 
> will soon cease to exist, will be no more, join the choir invisible, and
> become an ex-object; and thusly be able to do something sensible about it.
 
> Except that they won't work here.
 
The main rationale behind rvalue references is to provide support for
move semantics, and ref-qualifiers on members have this goal too.
I think that what you are trying to achieve here is some hybrid design
wherein a subobject may be copied (or possibly moved?) out of a
temporary object.
I see that you are complaining about a theoretical asymmetry in the
language design where it provides rvalue references and no rvalue
pointers, however I don't see that as a flaw.
 
My earlier reference to object lifetime was not by accident. What you
are trying to achieve appears to be some ownership model wherein a
contained object may survive its container.
If this is the goal, then it is better to make such choice explicit by
providing specific copy/move/reference accessors, instead of relying on
the semantics of temporaries. That is IMO, of course.
 
 
> Again, they'll work just fine when invoked as (*ptr).method(), (if
> appropriately overloaded) but not as ptr->method(). No way to make that
> work.
 
Indeed not, but then if ownership is allocated to std::unique_ptr, then
it is better to manage the entire object lifetime through such
unique_ptr, instead of splitting this responsibility between container
and contained.
 
Sam <sam@email-scan.com>: May 26 06:46PM -0400

Manfred writes:
 
> My earlier reference to object lifetime was not by accident. What you are
> trying to achieve appears to be some ownership model wherein a contained
> object may survive its container.
 
Actually, it's the opposite: the contained object may not survive its
container.
 
And in case of std::unique_ptr, it's guaranteed not to survive its container.
 
> Indeed not, but then if ownership is allocated to std::unique_ptr, then it
> is better to manage the entire object lifetime through such unique_ptr,
> instead of splitting this responsibility between container and contained.
 
It is true that (in this context) one can explicitly assign the container,
and thus preserve ownership:
 
auto office=building.penthouse();
 
const auto &available_hours=office->get_available_hours();
 
Here, the returned value from build.penthouse() is assigned to "office". The
returned value happens to be a unique_ptr, but I don't really care. My
contract, is that penthouse() returns a container for an office of some kind
that implements get_available_hours() whose lifetime exists as long as the
object that implements get_available_hours() exists.
 
I can't do
 
const auto &available_hours=building.penthouse()->get_available_hours();
 
This will leave me with dangling reference. Instead I have to assign
whatever penthouse() returns to an auto, and then dereference it. And then
this auto object exists until the end of the scope too, which might have
other side effects, as well.
 
But suppose you could overload -> so that it ends up calling either an & or
an && overload in the contained object, depending upon whether the container
itself is also & or &&. Then what we can do now? Well:
 
const auto &available_hours=office->get_available_hours();
 
This still calls the regular & overload, which returns the same const reference,
to the avilable hours. But now:
 
const auto &available_hours=building.penthouse()->get_available_hours();
 
Much shorter, cleaner, and to the point. This uses the currently non-
existent mechanism to invoke the && overload, which returns a prvalue
instead of a const reference. Its lifetime now gets automatically extended,
as per the current rules of doing so.
 
Also: whatever object penthouse() returned has served its purpose, and can
go away, and it doesn't have to exist until the end of the scope.
 
But, to achieve the same results right now, one has to do
(*building.penthouse()).get_available_hours(), employing the operator*
overload in penthouse's returned object, which returns an && instead of &.
This is fugly.
Manfred <noname@add.invalid>: May 26 12:52PM +0200

On 5/26/2020 1:21 AM, Mr Flibble wrote:
 
> No, it is, a) meaningless as far as the English language is concerned
> and b) circular reasoning from the point of view of logic.
> SELF-REFERENTIAL DEFINITIONS ARE BOGUS (SEE ANY DICTIONARY).
 
class Fruit
{
// generalization of apple
};
 
class Apple : public Fruit
{
// specialization of fruit
};
 
Using the "is a" logic relationship:
An apple "is a" fruit.
 
In human language:
An apple is a fruit, but not all fruits are apples.
 
How else would you express the above in proper English?
 
Back to the topic:
The standard says that "Iterators are a generalization of pointers",
i.e. a pointer is an iterator, but not all iterators are pointers [*].
 
This is a "is a" relationship, in your step 3) above you assume that a
"is a" relationship is an identity. In logic it is not.
Hence my correction of your step 3) above.
 
 
[*] exceptions of null pointers and singular iterators left out because
they are, well... exceptions.
 
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: May 26 12:18PM +0100

On 26/05/2020 11:52, Manfred wrote:
> };
 
> Using the "is a" logic relationship:
> An apple "is a" fruit.
 
Yes, it is, however:
 
class Apple : public Apple
{
// what we are actually taking about which is bogus.
};
 
 
> In human language:
> An apple is a fruit, but not all fruits are apples.
 
I already used that as an example.
 
 
> How else would you express the above in proper English?
 
Try reading a post properly before replying to it.
 
> The standard says that "Iterators are a generalization of pointers", i.e. a pointer is an iterator, but not all iterators are pointers [*].
 
> This is a "is a" relationship, in your step 3) above you assume that a "is a" relationship is an identity. In logic it is not.
> Hence my correction of your step 3) above.
 
See above for why you remain wrong.
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne 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."
James Kuyper <jameskuyper@alumni.caltech.edu>: May 26 06:58AM -0700

On Monday, May 25, 2020 at 6:19:06 PM UTC-4, Mr Flibble wrote:
...
 
> 1) Iterator is an abstraction of pointer
> 2) Given (1) pointer is an iterator
> 3) Given (1) and (2) iterator is an abstraction of iterator
 
If you think that has even the remotest connection to what we were saying, that misconception would explain a lot.
 
> 2) Learn fucking English
 
While I'm familiar with many different dialects of English, "fucking
English" is not one of them. If the rules of that dialect are
sufficiently different from those of conventional English to support
your claims, I'd prefer not to become familiar with it.
 
And because you seem dumb enough that this might need to be said: yes, I
know exactly what you actually meant by that sentence; I'm just
expressing my disapproval, both of what you said, and of how you chose
to say it, by deliberately misinterpreting it.
 
I see no point in further discussion. Feel free to respond with a vulgar
insult, as is your wont.
Mr Flibble <flibbleREMOVETHISBIT@i42.co.uk>: May 26 09:22PM +0100

On 26/05/2020 14:58, James Kuyper wrote:
>> 2) Given (1) pointer is an iterator
>> 3) Given (1) and (2) iterator is an abstraction of iterator
 
> If you think that has even the remotest connection to what we were saying, that misconception would explain a lot.
 
That is EXACTLY what you are saying, mate. So I assume you are now backtracking as I have finally got through your thick skull to show you your error in SELF REFERENTIAL CIRCULAR LOGIC.
 
/Flibble
 
--
"Snakes didn't evolve, instead talking snakes with legs changed into snakes." - Rick C. Hodgin
 
"You won't burn in hell. But be nice anyway." – Ricky Gervais
 
"I see Atheists are fighting and killing each other again, over who doesn't believe in any God the most. Oh, no..wait.. that never happens." – Ricky Gervais
 
"Suppose it's all true, and you walk up to the pearly gates, and are confronted by God," Byrne 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."
Bonita Montero <Bonita.Montero@gmail.com>: May 26 04:44PM +0200

> Can anyone explain what the purpose is for the keyword typename in the code above?
 
It's because C++-parsers are stupid.
Pavel <pauldontspamtolk@removeyourself.dontspam.yahoo>: May 26 12:16AM -0400

Alf P. Steinbach wrote:
> representing pointers with `intptr_t` values. Instead of using time on
> adapting sorting to that, I would spend the time fixing the design
> issues that have caused the odours. And then just use `std::sort`.
Parallel array representations are often more efficient than the
alternatives so it might turn out there is nothing to fix.
 
E.g. given N locations defined by x, y and h (height) coordinates and a
need to move all N locations up or down, it can be done most efficiently
when the locations are represented by 3 parallel arrays e.g. xs, ys and hs.
 
Also, more library and/or hardware support is often available for
parallel arrays of basic types than is for a single array of
user-defined compound objects (e.g. think vector operations).
 
 
> - Alf
 
-Pavel
Jorgen Grahn <grahn+nntp@snipabacken.se>: May 26 06:00AM

On Tue, 2020-05-26, Pavel wrote:
...
> Also, more library and/or hardware support is often available for
> parallel arrays of basic types than is for a single array of
> user-defined compound objects (e.g. think vector operations).
 
Surely it makes no difference if you copy 100 int or 50 std::pair<int, int>?
I'd expect a quality compiler to optimize them the same way.
 
(Of course it's different if things like std::strings are involved.)
 
/Jorgen
 
--
// Jorgen Grahn <grahn@ Oo o. . .
\X/ snipabacken.se> O o .
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: