Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #74622 > unrolled thread

Memory and error management approaches

Started by"Morten W. Petersen" <morphex@gmail.com>
First post2015-11-02 10:17 +0100
Last post2015-11-03 18:15 -0800
Articles 20 on this page of 49 — 12 participants

Back to article view | Back to comp.lang.c


Contents

  Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-02 10:17 +0100
    Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-02 22:25 +1300
      Re: Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-02 10:36 +0100
        Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-02 22:41 +1300
          Re: Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-02 11:05 +0100
            Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-02 12:15 +0000
              Re: Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-02 20:31 +0100
            Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 09:48 +1300
              Re: Memory and error management approaches supercat@casperkitty.com - 2015-11-02 13:17 -0800
                Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 10:29 +1300
                  Re: Memory and error management approaches supercat@casperkitty.com - 2015-11-02 13:48 -0800
              Re: Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-02 22:31 +0100
                Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 11:02 +1300
                  Re: Memory and error management approaches supercat@casperkitty.com - 2015-11-02 15:21 -0800
                Re: Memory and error management approaches <william@wilbur.25thandClement.com> - 2015-11-03 17:24 -0800
                  Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-04 14:38 +1300
                    Re: Memory and error management approaches <william@wilbur.25thandClement.com> - 2015-11-04 10:48 -0800
                      Re: Memory and error management approaches supercat@casperkitty.com - 2015-11-04 11:28 -0800
                      Re: Memory and error management approaches James Kuyper <jameskuyper@verizon.net> - 2015-11-04 14:54 -0500
                        Re: Memory and error management approaches Gareth Owen <gwowen@gmail.com> - 2015-11-06 07:50 +0000
                          Re: Memory and error management approaches <william@wilbur.25thandClement.com> - 2015-11-06 11:40 -0800
                            Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-07 09:38 +1300
                            Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-06 20:55 +0000
                              Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-07 02:23 -0800
                                Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-07 11:29 +0000
                                  Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-07 04:18 -0800
                                    Re: Memory and error management approaches asetofsymbols@gmail.com - 2015-11-07 05:41 -0800
                                      Re: Memory and error management approaches asetofsymbols@gmail.com - 2015-11-07 06:27 -0800
                                    Re: Memory and error management approaches Sjouke Burry <burrynulnulfour@ppllaanneett.nnll> - 2015-11-07 18:20 +0100
                                      Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-07 10:28 -0800
                                        Re: Memory and error management approaches gazelle@shell.xmission.com (Kenny McCormack) - 2015-11-07 19:01 +0000
                                Re: Memory and error management approaches raltbos@xs4all.nl (Richard Bos) - 2015-11-10 16:14 +0000
                                Re: Memory and error management approaches Gareth Owen <gwowen@gmail.com> - 2015-11-10 21:13 +0000
                      Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-10 19:26 +0000
                  Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-03 18:25 -0800
                  Re: Memory and error management approaches "Morten W. Petersen" <morphex@gmail.com> - 2015-11-06 10:05 +0100
      Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-02 02:15 -0800
        Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-02 12:01 +0000
          Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-02 06:05 -0800
            Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-02 17:18 +0000
              Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-02 09:27 -0800
                Re: Memory and error management approaches Jorgen Grahn <grahn+nntp@snipabacken.se> - 2015-11-02 23:02 +0000
                Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 12:07 +1300
                  Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-02 15:23 -0800
              Re: Memory and error management approaches supercat@casperkitty.com - 2015-11-02 10:28 -0800
        Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 09:34 +1300
          Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-02 14:05 -0800
            Re: Memory and error management approaches Ian Collins <ian-news@hotmail.com> - 2015-11-03 11:27 +1300
              Re: Memory and error management approaches Malcolm McLean <malcolm.mclean5@btinternet.com> - 2015-11-03 18:15 -0800

Page 1 of 3  [1] 2 3  Next page →


#74622 — Memory and error management approaches

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-11-02 10:17 +0100
SubjectMemory and error management approaches
Message-ID<n179ne$64b$1@speranza.aioe.org>
Hi there.

So I'm working on my XML parser, and I'm thinking of ways to manage
memory..

The design of the program will be one that uses loops rather than
recursion, so exhausting the stack is unlikely.

I was thinking of passing a parser object around, and on that parser
object, link to a structure that contains references to all memory
locations that need to be freed, all streams that need to be closed
and so on, in the case of success or failure.

And then have a function that goes through this error structure and
deals with everything.

This should work regardless the parsing succeeds or fails, and would
also work with setjmp/longjmp.

Any thoughts on this?  A while ago someone wrote on comp.lang.c about
writing a custom memory manager for performance; is that something that
could be coupled with all of this?

-Morten

[toc] | [next] | [standalone]


#74624

FromIan Collins <ian-news@hotmail.com>
Date2015-11-02 22:25 +1300
Message-ID<d9ooh3F6ovuU4@mid.individual.net>
In reply to#74622
Morten W. Petersen wrote:
> Hi there.
>
> So I'm working on my XML parser, and I'm thinking of ways to manage
> memory..
>
> The design of the program will be one that uses loops rather than
> recursion, so exhausting the stack is unlikely.
>
> I was thinking of passing a parser object around, and on that parser
> object, link to a structure that contains references to all memory
> locations that need to be freed, all streams that need to be closed
> and so on, in the case of success or failure.

Or just use C++....

> And then have a function that goes through this error structure and
> deals with everything.
>
> This should work regardless the parsing succeeds or fails, and would
> also work with setjmp/longjmp.

You should forget about setjmp/longjmp and just handle errors locally.

> Any thoughts on this?  A while ago someone wrote on comp.lang.c about
> writing a custom memory manager for performance; is that something that
> could be coupled with all of this?

Most of the platforms I'm familiar with provide specialised memory 
allocator libraries, you shouldn't have to roll yet another one for 
something as simple as XML parsing.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74626

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-11-02 10:36 +0100
Message-ID<n17app$82n$1@speranza.aioe.org>
In reply to#74624
On 02.11.2015 10:25, Ian Collins wrote:
[...]
>> And then have a function that goes through this error structure and
>> deals with everything.
>>
>> This should work regardless the parsing succeeds or fails, and would
>> also work with setjmp/longjmp.
>
> You should forget about setjmp/longjmp and just handle errors locally.

Why?

>> Any thoughts on this?  A while ago someone wrote on comp.lang.c about
>> writing a custom memory manager for performance; is that something that
>> could be coupled with all of this?
>
> Most of the platforms I'm familiar with provide specialised memory
> allocator libraries, you shouldn't have to roll yet another one for
> something as simple as XML parsing.

Well it will also provide a (simple?) DOM and writer as well.

So for example a search could be optimized by having certain things
on one memory page etc.

-Morten

[toc] | [prev] | [next] | [standalone]


#74627

FromIan Collins <ian-news@hotmail.com>
Date2015-11-02 22:41 +1300
Message-ID<d9opetF6ovuU6@mid.individual.net>
In reply to#74626
Morten W. Petersen wrote:
> On 02.11.2015 10:25, Ian Collins wrote:
> [...]
>>> And then have a function that goes through this error structure and
>>> deals with everything.
>>>
>>> This should work regardless the parsing succeeds or fails, and would
>>> also work with setjmp/longjmp.
>>
>> You should forget about setjmp/longjmp and just handle errors locally.
>
> Why?

It will inevitably end in tears and/or much unnecessary complexity.

>>> Any thoughts on this?  A while ago someone wrote on comp.lang.c about
>>> writing a custom memory manager for performance; is that something that
>>> could be coupled with all of this?
>>
>> Most of the platforms I'm familiar with provide specialised memory
>> allocator libraries, you shouldn't have to roll yet another one for
>> something as simple as XML parsing.
>
> Well it will also provide a (simple?) DOM and writer as well.
>
> So for example a search could be optimized by having certain things
> on one memory page etc.

Trying to add such micro-optimisations on modern CPUs is seldom worth 
the effort.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74631

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-11-02 11:05 +0100
Message-ID<n17cgd$cf2$1@speranza.aioe.org>
In reply to#74627
On 02.11.2015 10:41, Ian Collins wrote:
> Morten W. Petersen wrote:
>> On 02.11.2015 10:25, Ian Collins wrote:
>> [...]
>>>> And then have a function that goes through this error structure and
>>>> deals with everything.
>>>>
>>>> This should work regardless the parsing succeeds or fails, and would
>>>> also work with setjmp/longjmp.
>>>
>>> You should forget about setjmp/longjmp and just handle errors locally.
>>
>> Why?
>
> It will inevitably end in tears and/or much unnecessary complexity.

Well, the error structure will contain pointers and be maybe 20 pointers
big, and these pointers will in turn be linked lists if there is more
than one entry..

If all dynamically allocated memory is freed and streams are closed on a 
longjmp, what's the problem?

And by the way, is it proper practice to close streams when done with
them, or should that be left to the caller?

>>>> Any thoughts on this?  A while ago someone wrote on comp.lang.c about
>>>> writing a custom memory manager for performance; is that something that
>>>> could be coupled with all of this?
>>>
>>> Most of the platforms I'm familiar with provide specialised memory
>>> allocator libraries, you shouldn't have to roll yet another one for
>>> something as simple as XML parsing.
>>
>> Well it will also provide a (simple?) DOM and writer as well.
>>
>> So for example a search could be optimized by having certain things
>> on one memory page etc.
>
> Trying to add such micro-optimisations on modern CPUs is seldom worth
> the effort.

Well that would depend on the data type and size wouldn't it?

-Morten

[toc] | [prev] | [next] | [standalone]


#74637

FromJorgen Grahn <grahn+nntp@snipabacken.se>
Date2015-11-02 12:15 +0000
Message-ID<slrnn3eku6.5q5.grahn+nntp@frailea.sa.invalid>
In reply to#74631
On Mon, 2015-11-02, Morten W. Petersen wrote:
...
[His XML parser project]

> And by the way, is it proper practice to close streams when done with
> them, or should that be left to the caller?

The one who opened the file should be the one to close it.

But it would probably be nice if your core parser wasn't aware of I/O,
but could be fed chunks of data:

  int parser_feed(Parser*, const char* data, size_t len);

Then you could build variants which work on FILE*, or strings, or
memory-mapped files ... on top of that.

/Jorgen

-- 
  // Jorgen Grahn <grahn@  Oo  o.   .     .
\X/     snipabacken.se>   O  o   .

[toc] | [prev] | [next] | [standalone]


#74689

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-11-02 20:31 +0100
Message-ID<n18dmt$2uc$1@speranza.aioe.org>
In reply to#74637
On 02.11.2015 13:15, Jorgen Grahn wrote:
> On Mon, 2015-11-02, Morten W. Petersen wrote:
> ...
> [His XML parser project]
>
>> And by the way, is it proper practice to close streams when done with
>> them, or should that be left to the caller?
>
> The one who opened the file should be the one to close it.
>
> But it would probably be nice if your core parser wasn't aware of I/O,
> but could be fed chunks of data:
>
>    int parser_feed(Parser*, const char* data, size_t len);
>
> Then you could build variants which work on FILE*, or strings, or
> memory-mapped files ... on top of that.

That's a good idea, enabling users to use it in that way, will
be added.

-Morten

[toc] | [prev] | [next] | [standalone]


#74698

FromIan Collins <ian-news@hotmail.com>
Date2015-11-03 09:48 +1300
Message-ID<d9q0hqF7v31U2@mid.individual.net>
In reply to#74631
Morten W. Petersen wrote:
> On 02.11.2015 10:41, Ian Collins wrote:
>> Morten W. Petersen wrote:
>>> On 02.11.2015 10:25, Ian Collins wrote:
>>> [...]
>>>>> And then have a function that goes through this error structure and
>>>>> deals with everything.
>>>>>
>>>>> This should work regardless the parsing succeeds or fails, and would
>>>>> also work with setjmp/longjmp.
>>>>
>>>> You should forget about setjmp/longjmp and just handle errors locally.
>>>
>>> Why?
>>
>> It will inevitably end in tears and/or much unnecessary complexity.
>
> Well, the error structure will contain pointers and be maybe 20 pointers
> big, and these pointers will in turn be linked lists if there is more
> than one entry..
>
> If all dynamically allocated memory is freed and streams are closed on a
> longjmp, what's the problem?

You have introduced a laborious, manual and therefore error prone 
overhead to each resource allocation and release.

There are good reasons why no attempt at bolting on an exception 
mechanism on to C has ever caught on.

> And by the way, is it proper practice to close streams when done with
> them, or should that be left to the caller?

He who opens, closes.

>>>>> Any thoughts on this?  A while ago someone wrote on comp.lang.c about
>>>>> writing a custom memory manager for performance; is that something that
>>>>> could be coupled with all of this?
>>>>
>>>> Most of the platforms I'm familiar with provide specialised memory
>>>> allocator libraries, you shouldn't have to roll yet another one for
>>>> something as simple as XML parsing.
>>>
>>> Well it will also provide a (simple?) DOM and writer as well.
>>>
>>> So for example a search could be optimized by having certain things
>>> on one memory page etc.
>>
>> Trying to add such micro-optimisations on modern CPUs is seldom worth
>> the effort.
>
> Well that would depend on the data type and size wouldn't it?

The time to look at custom allocation is after extensive testing and 
profiling shows a bottleneck with dynamic memory.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74702

Fromsupercat@casperkitty.com
Date2015-11-02 13:17 -0800
Message-ID<cad90f0b-d6a2-4069-8c88-8283ea338ae5@googlegroups.com>
In reply to#74698
On Monday, November 2, 2015 at 2:49:08 PM UTC-6, Ian Collins wrote:
> There are good reasons why no attempt at bolting on an exception 
> mechanism on to C has ever caught on.

It's all very nice and convenient to assume that things will always behave
as expected, at least until the unexpected happens.  Once one opens up that
can of worms, there often is no really good approach--the best one can do
is try to manage the least-evil approach.  The scenario where I see a
longjmp-based recovery as being appropriate would be one where inner-level
code wouldn't be likely to be acquiring and releasing many resources that
outer-level code didn't know about, so it wouldn't be necessary to use
mid-level setjmp for most scenarios.

> The time to look at custom allocation is after extensive testing and 
> profiling shows a bottleneck with dynamic memory.

I've used custom allocators often in embedded systems where requirements
could be met in such a way that fragmentation would never occur.  On hosted
systems, non-library code should generally use malloc/free, but that doesn't
mean library code shouldn't allow clients to use some other forms of
allocation that may be more appropriate to their needs.

[toc] | [prev] | [next] | [standalone]


#74703

FromIan Collins <ian-news@hotmail.com>
Date2015-11-03 10:29 +1300
Message-ID<d9q2t5F7v31U4@mid.individual.net>
In reply to#74702
supercat@casperkitty.com wrote:
> On Monday, November 2, 2015 at 2:49:08 PM UTC-6, Ian Collins wrote:
>> There are good reasons why no attempt at bolting on an exception
>> mechanism on to C has ever caught on.
>
> It's all very nice and convenient to assume that things will always behave
> as expected, at least until the unexpected happens.  Once one opens up that
> can of worms, there often is no really good approach--the best one can do
> is try to manage the least-evil approach.  The scenario where I see a
> longjmp-based recovery as being appropriate would be one where inner-level
> code wouldn't be likely to be acquiring and releasing many resources that
> outer-level code didn't know about, so it wouldn't be necessary to use
> mid-level setjmp for most scenarios.

True enough but once added, longjmp based recovery makes the code 
vulnerable to any changes between the jump and landing site which do 
allocate a resource.  In short it makes the code fragile.

>> The time to look at custom allocation is after extensive testing and
>> profiling shows a bottleneck with dynamic memory.
>
> I've used custom allocators often in embedded systems where requirements
> could be met in such a way that fragmentation would never occur.  On hosted
> systems, non-library code should generally use malloc/free, but that doesn't
> mean library code shouldn't allow clients to use some other forms of
> allocation that may be more appropriate to their needs.

You wouldn't really want a library to use a different allocation scheme 
to the rest of the application, especially if the scheme allocates its 
own working memory.

In cases such as parsers, the library writer has no way of knowing which 
allocation scheme is appropriate for a particular use case.  Consider 
the differing requirements of two use cases I mentioned earlier: small 
SOAP packets and large office documents.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74706

Fromsupercat@casperkitty.com
Date2015-11-02 13:48 -0800
Message-ID<3c8abe2a-c26c-468f-9eff-2cc496a15794@googlegroups.com>
In reply to#74703
On Monday, November 2, 2015 at 3:29:24 PM UTC-6, Ian Collins wrote:
> True enough but once added, longjmp based recovery makes the code 
> vulnerable to any changes between the jump and landing site which do 
> allocate a resource.  In short it makes the code fragile.

Using longjmp without providing mid-level hooks may create problems for
which no reasonable solution exists.  In cases where manually returning
up the call stack would be workable, that's often better, but in cases
where the alternative to a longjmp would be a core dump, a longjmp can
offer the possibility of handling things more gracefully.

> You wouldn't really want a library to use a different allocation scheme 
> to the rest of the application, especially if the scheme allocates its 
> own working memory.

In some cases it may be useful to malloc a chunk of memory and then sub-
allocate chunks from that for temporary usage, especially if there is a
frequent pattern of allocate temporary; allocate persistent; copy data
from temporary to persistent (possibly reformatting it in the process);
release temp.  If all the temporary storage will be repeatedly allocated,
released in LIFO order, re-allocated, etc. having a block of memory which
is dedicated to that purpose can greatly reduce fragmentation elsewhere.

> In cases such as parsers, the library writer has no way of knowing which 
> allocation scheme is appropriate for a particular use case.  Consider 
> the differing requirements of two use cases I mentioned earlier: small 
> SOAP packets and large office documents.

That's why I was suggesting the library should let the client decide.  If
the client has no problem with malloc/free, the library shouldn't either.

[toc] | [prev] | [next] | [standalone]


#74705

From"Morten W. Petersen" <morphex@gmail.com>
Date2015-11-02 22:31 +0100
Message-ID<n18kna$jnt$1@speranza.aioe.org>
In reply to#74698
On 02.11.2015 21:48, Ian Collins wrote:
> Morten W. Petersen wrote:
[...]
>> Well, the error structure will contain pointers and be maybe 20 pointers
>> big, and these pointers will in turn be linked lists if there is more
>> than one entry..
>>
>> If all dynamically allocated memory is freed and streams are closed on a
>> longjmp, what's the problem?
>
> You have introduced a laborious, manual and therefore error prone
> overhead to each resource allocation and release.
>
> There are good reasons why no attempt at bolting on an exception
> mechanism on to C has ever caught on.
[...]
>>> Trying to add such micro-optimisations on modern CPUs is seldom worth
>>> the effort.
>>
>> Well that would depend on the data type and size wouldn't it?
>
> The time to look at custom allocation is after extensive testing and
> profiling shows a bottleneck with dynamic memory.

The reason I'm asking about custom allocation is that if I do some
custom memory allocation, it isn't a big deal to also setup info
that can be used on setjmp/longjmp tear-downs.

A bit of what I've seen online is that memory allocators have speed
benefits..

Also, seeing this:

http://www.pjsip.org/pjlib/docs/html/group__PJ__POOL__GROUP.htm

I can use a memory pool, and destroy it after a longjmp and memory
has been handled.

-Morten

[toc] | [prev] | [next] | [standalone]


#74708

FromIan Collins <ian-news@hotmail.com>
Date2015-11-03 11:02 +1300
Message-ID<d9q4r0F7v31U6@mid.individual.net>
In reply to#74705
Morten W. Petersen wrote:
> On 02.11.2015 21:48, Ian Collins wrote:
>>
>> The time to look at custom allocation is after extensive testing and
>> profiling shows a bottleneck with dynamic memory.
>
> The reason I'm asking about custom allocation is that if I do some
> custom memory allocation, it isn't a big deal to also setup info
> that can be used on setjmp/longjmp tear-downs.
>
> A bit of what I've seen online is that memory allocators have speed
> benefits..

Any coding technique can have speed benefits under specific conditions. 
  I have used custom allocators, mainly in embedded applications, where 
the allocation patterns were known in advance and memory budgets were 
tight.  I would only consider one on a hosted application if real world 
testing justified it.

> Also, seeing this:
>
> http://www.pjsip.org/pjlib/docs/html/group__PJ__POOL__GROUP.htm
>
> I can use a memory pool, and destroy it after a longjmp and memory
> has been handled.>

I wouldn't bother until you can prove an advantage. Enabling longjump 
hackery isn't one in my book.

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74721

Fromsupercat@casperkitty.com
Date2015-11-02 15:21 -0800
Message-ID<71cb8c79-5ffe-4fbf-9ffa-60fb4ebcc4b2@googlegroups.com>
In reply to#74708
On Monday, November 2, 2015 at 4:02:20 PM UTC-6, Ian Collins wrote:
> I wouldn't bother until you can prove an advantage. Enabling longjump 
> hackery isn't one in my book.

Unwinding failed object construction is generally problematic no matter what
one does.  If the input stream dies or one has sufficient advance warning of memory depletion, it may be possible to set an "object invalid" flag and jinx
the input functions to pretend they see whatever kind of end tag they're
expecting, let construction run its course, and then deconstruct the object
in the usual manner.  If, however, code finds itself without warning in the
middle of constructing an object with no way to finish building something
that can be given to the "deconstruct object" function, having a way to say
"all the stuff I allocated using this context object is junk--get rid of it"
can be much easier and more robust than scattering code throughout the
object construction logic to handle failed constructor cleanup, whether one
uses longjmp or a chain of "if (error) return;" logic.

[toc] | [prev] | [next] | [standalone]


#74788

From<william@wilbur.25thandClement.com>
Date2015-11-03 17:24 -0800
Message-ID<6b3ogc-uob.ln1@wilbur.25thandClement.com>
In reply to#74705
Morten W. Petersen <morphex@gmail.com> wrote:
> On 02.11.2015 21:48, Ian Collins wrote:
>> Morten W. Petersen wrote:
> [...]
>>> Well, the error structure will contain pointers and be maybe 20 pointers
>>> big, and these pointers will in turn be linked lists if there is more
>>> than one entry..
>>>
>>> If all dynamically allocated memory is freed and streams are closed on a
>>> longjmp, what's the problem?
>>
>> You have introduced a laborious, manual and therefore error prone
>> overhead to each resource allocation and release.
>>
>> There are good reasons why no attempt at bolting on an exception
>> mechanism on to C has ever caught on.
> [...]
>>>> Trying to add such micro-optimisations on modern CPUs is seldom worth
>>>> the effort.
>>>
>>> Well that would depend on the data type and size wouldn't it?
>>
>> The time to look at custom allocation is after extensive testing and
>> profiling shows a bottleneck with dynamic memory.
> 
> The reason I'm asking about custom allocation is that if I do some
> custom memory allocation, it isn't a big deal to also setup info
> that can be used on setjmp/longjmp tear-downs.
> 
> A bit of what I've seen online is that memory allocators have speed
> benefits..

IMO, the best reason to use a custom allocation scheme is to improve the
quality of your code, not the performance. By improving the quality I mean
improving readability, permitting simplifications, etc.

But event that's a trade-off. See, e.g., OpenBSD's take on the OpenSSL
Heartbleed fiasco, where they claim the biggest sin was that by using a
custom allocator OpenSSL circumvented the sophisticated attack mitigations
in OpenBSD's system allocator.

> 
> Also, seeing this:
> 
> http://www.pjsip.org/pjlib/docs/html/group__PJ__POOL__GROUP.htm

A few criticisms:

1) The more sophisticated the allocator, the more complex it is. Ultimately
you're just substituting one general purpose allocator for another. Modern
system allocators already implement pools and other strategies. They're not
all buddy allocators.

2) Debugging is usually much easier when dealing with the system allocator.
For any debugging feature claimed by the library author, the capability and
tooling for the system allocator will be even better, _especially_ on
systems like Solaris, Linux, and OS X. (I can't speak for Window's CRT.)

3) Adding third-party dependencies, especially for mundane stuff like memory
management, can become a maintanence headache, and possibly a source of
frustration for users.

4) Custom allocators--for improving performance or code quality--are best
when targeted at specific parts of your application. E.g. using a simple
object stack/bump allocator for a parser, or a slab allocator for object
construction. In these situations, the implementation is often trivial, and
can provide benefits beyond what more general libraries offer. By looking at
third-party libraries, you're already conceding that your approach is not
focused on your immediate problems.

> I can use a memory pool, and destroy it after a longjmp and memory
> has been handled.

Sure. I use that approach quite often. I've also used longjmp for error
handling. But I only use these techniques in particular subcomponents, where
the cost+benefit is maximized, and the implementation doesn't leak outside
the interface.

In terms of APIs, including internal APIs, you're almost always better off
sticking to the system facilities, as you would most other languages. More
importantly, sticking to tried-and-true patterns (e.g. RAII[1]) is far and
away the most critical choice you can make. Obsessing over memory allocation
is one of the favorite pastimes of C newbies (and, unfortunately, even some
longtime C programmers), alongside dreaming of ways to abuse pointers and
type punning. Certainly I went through that phase, and years later am still
dealing with the costs.


[1] RAII as a discipline works just as well in C as in C++. Despite lacking
automatic destructors, the absolute benefit might be even greater in C
because memory management can be more burdensome, or at least verbose.

[toc] | [prev] | [next] | [standalone]


#74789

FromIan Collins <ian-news@hotmail.com>
Date2015-11-04 14:38 +1300
Message-ID<d9t5scFs0krU2@mid.individual.net>
In reply to#74788
william@wilbur.25thandClement.com wrote:
>
> [1] RAII as a discipline works just as well in C as in C++. Despite lacking
> automatic destructors, the absolute benefit might be even greater in C
> because memory management can be more burdensome, or at least verbose.

Could you expand on that statement?

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#74862

From<william@wilbur.25thandClement.com>
Date2015-11-04 10:48 -0800
Message-ID<fg0qgc-mgq.ln1@wilbur.25thandClement.com>
In reply to#74789
Ian Collins <ian-news@hotmail.com> wrote:
> william@wilbur.25thandClement.com wrote:
>>
>> [1] RAII as a discipline works just as well in C as in C++. Despite lacking
>> automatic destructors, the absolute benefit might be even greater in C
>> because memory management can be more burdensome, or at least verbose.
> 
> Could you expand on that statement?
> 

RAII was formalized as a method for ensuring object state consistency--or
rather minimizing the times and places that state is inconsistent--in order
to mitigate problems with exceptions. Because if an exception occurs when an
object is in an inconsistent state, you have problems. If you fix the
problems by sprinkling conditionals all over your code to handle the
additional number of states, you have even more problems.

Resource acquisition is initialization means, in negative terms, no _lazy_
initializations. That is, you shouldn't allocate an object and then lazily
allocate submembers. For example, you shouldn't allocate a FILE pointer and
lazily open the underlying file description. Because now that FILE object
has twice as many possible states.

Worse, it not only has more states, but in many cases you've multiplied the
number of failure scenarios. Now an ENOENT, for example, could happen on any
operation, not just at fopen time. (FILE is a poor example here because
there are other possible errors when reading or writing, but with many of
types of objects errors can only happen at construction time.)

To my mind, RAII is all about condensing resource acquisition into as few
places as possible.

Another principle that follows from RAII is maintaining single ownership. A
corollary, you mentioned elsethread, is he who allocates, deallocates. But
fundamentally it's about striving to maintain a tidy hierarchy of object
ownership at all times, even during construction. Among other things, this
allows many failure paths to merge up the stack via the tree of
constructors, so it can dramatically simplify error handling.

If you follow the discipline, manging object lifetime becomes simpler.
Object destruction becomes easier for the implementation because there are
fewer conditionals to worry about in the destructor. Destruction is easier
for the caller because there should be fewer interdependent relationships.
Likewise, when aborting a failed initialization, the error path is
simplified because unwinding a partially initialized object is made easier
as destruction of any initialied submembers is simpler. So even though C
lacks automatic destructors, RAII can still dramatically simplify
destruction.

I realize that RAII has a much more technical meaning, especially in the
context of C++. In C++ the discipline means applying several C++ specific
idioms, such as smart pointers (or similar constructs) for heap-allocated
objects so that lifetime is bound to the stack. But arguably that's just
syntactic sugar. You can implement OOP patterns in C, including virtual
methods, you just don't have the benefit of compiler constructs. Likewise,
for RAII you just need to manually ensure that all objects are ultimately
bound to a single stack reference, so destruction of the tree of resources
is as simple as calling a single destructor. (Or if they're not, that you're
employing some sort of reference counting, so even though ownership is
shared, the details can be hidden behind a single destructor so the contract
from the caller's perspective is the same.) Most of the burden of managing
object lifetime comes from the complexity of interdependencies and failure
modes; by following an RAII discipline you minimze both of those.

Ultimately one might simply consider this good code hygiene. But it helps if
there's a label you can use as a reference to the general methology, and I
think it's fair to appropriate RAII as that label. The compiler constructs
employed in C++ have analogous manual idioms in C.

[toc] | [prev] | [next] | [standalone]


#74865

Fromsupercat@casperkitty.com
Date2015-11-04 11:28 -0800
Message-ID<cc5e279a-ab81-4252-bab2-219c1b5e129a@googlegroups.com>
In reply to#74862
On Wednesday, November 4, 2015 at 1:00:21 PM UTC-6, wil...@wilbur.25thandclement.com wrote:
> Resource acquisition is initialization means, in negative terms, no _lazy_
> initializations. That is, you shouldn't allocate an object and then lazily
> allocate submembers. For example, you shouldn't allocate a FILE pointer and
> lazily open the underlying file description. Because now that FILE object
> has twice as many possible states.

I don't think RAII precludes lazy initialization, but it requires that it be
encapsulated via an object that has an *explicit* "awaiting initialization"
state, *and whose destructor can be safely called even when the object is in
that state*.

If an object lazily acquires a resource, it would be entirely possible (and
not particularly unexpected) that until the object has actually needed the
resource, nothing in the universe would care if it disappeared without its
destructor having been called first.  What's essential, though, is that even
if calling the destructor before the resource is acquired has no useful
effect, it's still *safe*.  Thus, code which owns the resource wrapper does
not have to concern itself with whether any resource has actually been
acquired; it can (and should) call the destructor in any case.

[toc] | [prev] | [next] | [standalone]


#74869

FromJames Kuyper <jameskuyper@verizon.net>
Date2015-11-04 14:54 -0500
Message-ID<n1dnm8$k1u$1@dont-email.me>
In reply to#74862
On 11/04/2015 01:48 PM, william@wilbur.25thandClement.com wrote:
> Ian Collins <ian-news@hotmail.com> wrote:
>> william@wilbur.25thandClement.com wrote:
>>>
>>> [1] RAII as a discipline works just as well in C as in C++. Despite lacking
>>> automatic destructors, the absolute benefit might be even greater in C
>>> because memory management can be more burdensome, or at least verbose.
>>
>> Could you expand on that statement?
...
> I realize that RAII has a much more technical meaning, especially in the
> context of C++. In C++ the discipline means applying several C++ specific
> idioms, such as smart pointers (or similar constructs) for heap-allocated
> objects so that lifetime is bound to the stack. But arguably that's just
> syntactic sugar.

I will argue that point - it is not "just" syntactic sugar - it's
extremely valuable syntactic sugar which renders inaccurate your claim
that it "works just as well in C as in C++". That syntactic sugar makes
it work a whole lot better in C++ than in C.
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#75053

FromGareth Owen <gwowen@gmail.com>
Date2015-11-06 07:50 +0000
Message-ID<8737wjk1lw.fsf@gmail.com>
In reply to#74869
James Kuyper <jameskuyper@verizon.net> writes:

> I will argue that point - it is not "just" syntactic sugar - it's
> extremely valuable syntactic sugar which renders inaccurate your claim
> that it "works just as well in C as in C++". That syntactic sugar makes
> it work a whole lot better in C++ than in C.

I completely agree.  The key to RAII is not that Resource Acquistion Is
Initialization but its converse -- End-of-Life Is *Automatic* Resource
Release.

You can fake the former easily in C ("no lazy initialisation") - the
converse is much much harder.  To release resources in C but you *have*
to do it all by hand (or use a GC, if the only resource you're
interested in is memory), which is absolutely not "works just as well in
C" unless you have unlimited programmers, unlimited patience or
unlimited time.

[toc] | [prev] | [next] | [standalone]


Page 1 of 3  [1] 2 3  Next page →

Back to top | Article view | comp.lang.c


csiph-web