Wednesday, August 24, 2022

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

JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 08:00PM +0300

First the code. The question below it:
 
------------------------
class Parent
{
public:
void foo2() {}
};
 
class Child
{
public:
Parent* m_parent{nullptr};
void foo() {
// can the validity of the raw pointer m_parent be checked?
m_parent->foo2();
}
};
 
void main()
{
Parent* parent = new Parent;
Child child;
child.m_parent = parent;
delete parent;
child.foo(); // any way this call knowing parent is now deleted?

}
 
------------------
 
Is there any way to check if a raw pointer is pointing to a valid object?
Because I have situations where I can only store raw pointers.
I know it can be done with shared pointers, but how about raw pointers?
Assuming I cannot change the Parent class in the above example.
Or is there any pattern applied to Child class... again assuming we
cannot change the Parent class at all.
Paavo Helde <eesnimi@osa.pri.ee>: Aug 24 08:24PM +0300

24.08.2022 20:00 JiiPee kirjutas:
>     child.m_parent = parent;
>     delete parent;
>     child.foo(); // any way this call knowing parent is now deleted?
 
No, there isn't any way. At best you can check if a pointer points to
memory page which is readable or writable for the process, but that does
not help much.
 
> Assuming I cannot change the Parent class in the above example.
> Or is there any pattern applied to Child class... again assuming we
> cannot change the Parent class at all.
 
The tedious way is to not delete parent without informing all the
children that the parent is dead.
 
A smarter pattern is smart pointers. You do not need to modify Parent
class for using smart pointers on it.
 
class Child
{
public:
std::weak_ptr<Parent> m_parent;
void foo() {
if (auto parent = m_parent.lock()) {
parent->foo2();
}
}
};
 
 
 
void main()
{
std::shared_ptr parent = std::allocate_shared<Parent>();
Child child;
child.m_parent = parent;
parent = nullptr; // deletes parent
child.foo(); // OK
}
Paavo Helde <eesnimi@osa.pri.ee>: Aug 24 08:28PM +0300

24.08.2022 20:24 Paavo Helde kirjutas:
 
>   std::shared_ptr parent = std::allocate_shared<Parent>();
 
Sorry, this should have been std::make_shared<Parent>();
JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 08:39PM +0300

On 24/08/2022 20:24, Paavo Helde wrote:
> The tedious way is to not delete parent without informing all the
> children that the parent is dead.
 
Yes but then would need to change the Parent. Which I cannot really do.
 
 
> A smarter pattern is smart pointers. You do not need to modify Parent
> class for using smart pointers on it.
 
Yes I know this... and this is obviously best way to do it if can.
JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 08:41PM +0300

On 24/08/2022 20:29, Stefan Ram wrote:
> You could write management functions that take care
> of the notifications required:
 
Yes possible, and good if can change parent. But that would need to
change the Parent class which I cannot always do.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Aug 24 10:44AM -0700


> No, there isn't any way. At best you can check if a pointer points to
> memory page which is readable or writable for the process, but that
> does not help much.
 
There's no portable way to do even that.
 
[...]
 
> void main()
 
Of course main returns int, not void. (I know that was in the parent
article.)
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 08:51PM +0300

On 24/08/2022 20:44, Keith Thompson wrote:
>> void main()
> Of course main returns int, not void. (I know that was in the parent
> article.)
 
but its shorter to type, hehe
JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 08:52PM +0300

On 24/08/2022 20:51, JiiPee wrote:
>> Of course main returns int, not void.  (I know that was in the parent
>> article.)
 
> but its shorter to type, hehe
 
actually compiles in visual studio
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Aug 24 11:59AM -0700

>>> article.)
>> but its shorter to type, hehe
 
> actually compiles in visual studio
 
Most C++ compilers aren't fully conforming by default. Any conforming
C++ implementation must diagnose `void main()` (and may then either
accept it or reject it).
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
Paavo Helde <eesnimi@osa.pri.ee>: Aug 24 11:32AM +0300


> Perhaps its time someone describes what they mean by idiomatic C++ code.
 
Perhaps the most visible difference is in that in proper C most of the
application level code deals with error checking and resource cleanup,
whereas in proper C++ most of the application level code implements
business logic. Example with two resources, one can easily imagine more.
A resource might be just a dynamically allocated array.
 
C:
 
int foo(int arg1, const char* arg2, X* presult) {
 
A* resource1 = NULL;
B* resource2 = NULL;
int retval;
 
if (PrepareResourceA(arg1, arg2, &resource1)!=0) {
goto FAILURE;
}
resource2 = PrepareResourceB(arg1, arg2, resource1);
if (!resource2) {
goto FAILURE;
}
if (CombineAB(resource1, resource2, presult)!=0) {
goto FAILURE;
}
// we know that ownership of B has moved over into result:
resource2 = NULL;
retval = 0; // success
goto CLEANUP;
 
FAILURE:
retval = -1;
goto CLEANUP;
 
CLEANUP:
if (resource1) {
ReleaseResourceA(resource1);
}
if (resource2) {
ReleaseResourceB(resource2);
}
 
return retval;
}
 
 
In C++, where errors are reported via exceptions, and ownership and
resource cleanup are automatic:
 
X foo(int arg1, std::string_view arg2) {
A resource1 = PrepareResourceA(arg1, arg2);
B resource2 = PrepareResourceB(arg1, arg2, resource1);
return CombineAB(std::move(resource1), std::move(resource2));
}
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 24 11:33AM +0100

> B resource2 = PrepareResourceB(arg1, arg2, resource1);
> return CombineAB(std::move(resource1), std::move(resource2));
> }
 
What you say is true, but you can make the point without writing clumsy
C and without assuming that the support functions have not been written
to handle prepare, combine and release actions for null pointers
correctly. The C code might, in fact, look like this:
 
A *resource1 = PrepareResourceA(arg1, arg2);
B *resource2 = PrepareResourceB(arg1, arg2, resource1);
bool result = CombineAB(resource1, resource2, presult);
ReleaseResourceA(resource1);
ReleaseResourceB(resource2);
return result;
 
--
Ben.
Malcolm McLean <malcolm.arthur.mclean@gmail.com>: Aug 24 04:37AM -0700

On Wednesday, 24 August 2022 at 11:33:51 UTC+1, Ben Bacarisse wrote:
> ReleaseResourceA(resource1);
> ReleaseResourceB(resource2);
> return result;
 
Superficially, that code looks tidy.
In reality it isn't. It's not clear to a mantaining programmer that the earlier calls
can fail and return null pointers.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 24 01:31PM +0100

>> return result;
 
> Superficially, that code looks tidy.
> In reality it isn't.
 
It is tidy. In reality. You mean you don't like it because a reader
has to know what the called function really do.
 
> It's not clear to a mantaining programmer that the earlier calls
> can fail and return null pointers.
 
The same is true of all well-written code. It's also true of the C++
about which you did not make the same comment.
 
--
Ben.
scott@slp53.sl.home (Scott Lurndal): Aug 24 01:56PM

> A resource1 = PrepareResourceA(arg1, arg2);
> B resource2 = PrepareResourceB(arg1, arg2, resource1);
> return CombineAB(std::move(resource1), std::move(resource2));
 
Your example presumes that error recovery is basically kill the job.
 
The error recovery for PrepareResourceA may be significantly different
from the error recovery for PrepareResourceB, and lumping both into
some upstream exception handler (potentially in a completely different translation
unit) makes everything more complicated.
 
Fix the errors as soon as possible, in line.
Muttley@dastardlyhq.com: Aug 24 02:09PM

On Wed, 24 Aug 2022 11:33:33 +0100
> bool result = CombineAB(resource1, resource2, presult);
 
AFAIK even C 2011 doesn't have "bool". Its defined as the (ugly) _Bool in C99.
Obviously you can typedef however.
Paavo Helde <eesnimi@osa.pri.ee>: Aug 24 05:18PM +0300

24.08.2022 16:56 Scott Lurndal kirjutas:
> some upstream exception handler (potentially in a completely different translation
> unit) makes everything more complicated.
 
> Fix the errors as soon as possible, in line.
 
With exceptions the exception can be easily handled at the most correct
level, be it 1 or 20 stack frames above the actual error. If the
exception is caught and handled inside a PrepareResource*(), then it's
all fine. The exception only reaches foo() if it was not possible to
handle it at lower level.
Muttley@dastardlyhq.com: Aug 24 02:25PM

On Wed, 24 Aug 2022 17:18:00 +0300
>exception is caught and handled inside a PrepareResource*(), then it's
>all fine. The exception only reaches foo() if it was not possible to
>handle it at lower level.
 
The trouble with exceptions is people use them as glorified gotos, often the
same people who think goto's are bad due to the not always obvious flow of
control (though I've never noticed that except in BASIC). The irony is
obviously lost on them.
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 24 03:31PM +0100

>> bool result = CombineAB(resource1, resource2, presult);
 
> AFAIK even C 2011 doesn't have "bool". Its defined as the (ugly) _Bool in C99.
> Obviously you can typedef however.
 
I did not show headers. C has had bool (defined in stdbool.h) ever
since it got _Bool.
 
None of the posted code is correct without a few declarations...
 
--
Ben.
Muttley@dastardlyhq.com: Aug 24 02:38PM

On Wed, 24 Aug 2022 15:31:32 +0100
>> Obviously you can typedef however.
 
>I did not show headers. C has had bool (defined in stdbool.h) ever
>since it got _Bool.
 
Fair enough, didn't know that. Whats the point of _Bool then? To stop
issues with C++ if a C99 file is included in a C++ project?
Ben Bacarisse <ben.usenet@bsb.me.uk>: Aug 24 03:57PM +0100

>>since it got _Bool.
 
> Fair enough, didn't know that. Whats the point of _Bool then? To stop
> issues with C++ if a C99 file is included in a C++ project?
 
Lots of old code defined bool. Suddenly making it a type keyword would
have broken that code. The identifier _Bool was reserved to the
implementation so it should not break anything.
 
--
Ben.
Keith Thompson <Keith.S.Thompson+u@gmail.com>: Aug 24 10:41AM -0700


> Lots of old code defined bool. Suddenly making it a type keyword would
> have broken that code. The identifier _Bool was reserved to the
> implementation so it should not break anything.
 
C23 will make bool, false, and true keywords.
 
http://www.open-std.org/jtc1/sc22/wg14/www/docs/n3047.pdf
 
--
Keith Thompson (The_Other_Keith) Keith.S.Thompson+u@gmail.com
Working, but not speaking, for Philips
void Void(void) { Void(); } /* The recursive call of the void */
ram@zedat.fu-berlin.de (Stefan Ram): Aug 24 05:29PM

>Or is there any pattern applied to Child class... again assuming we
>cannot change the Parent class at all.
 
You could write management functions that take care
of the notifications required:
 
child.m_parent = parent; ... delete parent;
 
becomes:
 
set_parent( child, parent ); ... delete_parent( parent );
 
. Now "delete_parent" can sent "MSG_INVALIDATE_PARENT" to
all children of the deleted parent, because it knows who
they are. Requirement: All parents are set via "set_parent"
and all such parents are deleted via "delete_parent".
JiiPee <kerrttuPoistaTama11@gmail.com>: Aug 24 07:27PM +0300

On 15/08/2022 15:17, Juha Nieminen wrote:
 
> (Technically speaking the rest of the function will be operating
> on a deleted object. While the rest of the function might not
> have any visible code, there may be destructors being run.)
 
I use MFC quite a lot, believer me or not. In MFC they seem to use it
... the windows object deletes itself when the window is destroyed.
 
by the way, is this allowed? returning a value after the object is deleted:
int MyClass::Foo()
{
delete this;
return 6;
}
Sam Varshavchik <mrsam@courier-mta.com>: Aug 23 08:48PM -0400

Lynn McGuire writes:
 
 
>> Message ends.
 
>> /Flibble
 
> Why ?
 
Because sometimes when people get bored they post bullshit to Usenet.
"Öö Tiib" <ootiib@hot.ee>: Aug 24 12:20AM -0700

On Wednesday, 24 August 2022 at 03:48:59 UTC+3, Sam Varshavchik wrote:
 
> >> /Flibble
 
> > Why ?
> Because sometimes when people get bored they post bullshit to Usenet.
 
That assertion is true but is unlikely to asked question.
Bullshit means that people are saying things that they have no idea
themselves if those are true, false, self-contradicting or ambiguous.
Mr Flibble well knows how to use C++ so can't be bullshit.
Lynn's question for example was ambiguous ... I did read it like
"Why message ends?"
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: