Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > C/C++ question about dynamic "static struct"

Reply
Thread Tools

C/C++ question about dynamic "static struct"

 
 
gwowen
Guest
Posts: n/a
 
      10-26-2012
On Oct 22, 8:02*pm, Les Cargill <(E-Mail Removed)> wrote:

> Fair enough; I'm not sure what you were driving at then. It's fully
> possible for 'C' programs to leave no widowed
> resources, memory or otherwise.


No-one has suggested otherwise. But that's not what RAII is. RAII is
mapping resource acquisition/release to object lifetime, and thus
using the *automatic* object construction/destruction semantics of the
language to ensure correct resource management.

C doesn't have meaningful automatic, deterministic construction/
destruction of non-trivial objects, so you can't do RAII (as it is
understood) in pure C.

> It's not even that difficult.


Well, there we'll have to differ.
 
Reply With Quote
 
 
 
 
Les Cargill
Guest
Posts: n/a
 
      10-26-2012
gwowen wrote:
> On Oct 22, 12:43 pm, ptyxs <(E-Mail Removed)> wrote:
>> Le 21/10/2012 19:54, Les Cargill a crit :
>> To badly> paraphrase Voltaire, "hell is other people's code*." The more of
>>> it there is, the more bugs there are.

>>
>> You probably meant 'to paraphrase Jean-Paul Sartre'...
>> Voltaire has nothing to do with that sentence...
>> Ptyxs

>
> Les was too busy correcting University Dons about category mistakes...
>


LOLz!

One a' them Frenchies, anyway! Trotting out "category error" on
usenet is problematic - it's hard enough just getting people to agree
to what words mean.

--
Les Cargill
 
Reply With Quote
 
 
 
 
Les Cargill
Guest
Posts: n/a
 
      10-26-2012
gwowen wrote:
> On Oct 22, 8:02 pm, Les Cargill <(E-Mail Removed)> wrote:
>
>> Fair enough; I'm not sure what you were driving at then. It's fully
>> possible for 'C' programs to leave no widowed
>> resources, memory or otherwise.

>
> No-one has suggested otherwise. But that's not what RAII is. RAII is
> mapping resource acquisition/release to object lifetime, and thus
> using the *automatic* object construction/destruction semantics of the
> language to ensure correct resource management.
>


Ach! Burry McDonald is nae true Scotsman

I still suspect that some of that contains distinctions without
differences. But I like the working definition you gave - "mapping
construction/deconstruction to object lifetimes." That's
clearer than what I'd seen before.

maybe I'll get the privilege of actually *learning* RAII ( through
doing a project with it ) rather than reading about it. Otherwise,
it's like pronouncing a word you've only read...

> C doesn't have meaningful automatic, deterministic construction/
> destruction of non-trivial objects, so you can't do RAII (as it is
> understood) in pure C.
>
>> It's not even that difficult.

>
> Well, there we'll have to differ.
>


Well, you have to *cheat* ( Ever use "atexit()"?).

The thing I was talking about really isn't GC, and it really
isn't ( apparently ) RAII. Got the thing(s) shipped, though.

It's probably closer to mark()/release().

--
Les Cargill




 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-26-2012
On 10/26/2012 08:53 AM, Les Cargill wrote:
> gwowen wrote:
>> On Oct 22, 8:02 pm, Les Cargill <(E-Mail Removed)> wrote:

....
> I still suspect that some of that contains distinctions without
> differences. But I like the working definition you gave - "mapping
> construction/deconstruction to object lifetimes." That's
> clearer than what I'd seen before.

....
>> C doesn't have meaningful automatic, deterministic construction/
>> destruction of non-trivial objects, so you can't do RAII (as it is
>> understood) in pure C.
>>
>>> It's not even that difficult.

>>
>> Well, there we'll have to differ.
>>

>
> Well, you have to *cheat* ( Ever use "atexit()"?).


Using an exit handler to deallocate a resource corresponds to RAII only
for objects whose lifetime ends precisely at the time the exit handler
is executed. That could only be objects with automatic storage duration
that are free()d inside the exit handler. All other objects have a
lifetime that ends too soon or too late to qualify as RAII. RAII is
often used for objects with lifetimes that could end long before the end
of the entire program.
--
James Kuyper
 
Reply With Quote
 
ImpalerCore
Guest
Posts: n/a
 
      10-26-2012
On Oct 26, 8:53*am, Les Cargill <(E-Mail Removed)> wrote:
> gwowen wrote:
> > On Oct 22, 8:02 pm, Les Cargill <(E-Mail Removed)> wrote:

>
> >> Fair enough; I'm not sure what you were driving at then. It's fully
> >> possible for 'C' programs to leave no widowed
> >> resources, memory or otherwise.

>
> > No-one has suggested otherwise. *But that's not what RAII is. *RAIIis
> > mapping resource acquisition/release to object lifetime, and thus
> > using the *automatic* object construction/destruction semantics of the
> > language to ensure correct resource management.

>
> Ach! Burry McDonald is nae true Scotsman
>
> I still suspect that some of that contains distinctions *without
> differences. But I like the working definition you gave - "mapping
> construction/deconstruction to object lifetimes." That's
> clearer than what I'd seen before.
>
> maybe I'll get the privilege of actually *learning* RAII ( through
> doing a project with it ) rather than *reading about it. Otherwise,
> it's like pronouncing a word you've only read...
>
> > C doesn't have meaningful automatic, deterministic construction/
> > destruction of non-trivial objects, so you can't do RAII (as it is
> > understood) in pure C.

>
> >> It's not even that difficult.

>
> > Well, there we'll have to differ.

>
> Well, you have to *cheat* ( Ever use "atexit()"?).
>
> The thing I was talking about really isn't GC, and it really
> isn't ( apparently ) RAII. Got the thing(s) shipped, though.
>
> It's probably closer to mark()/release().


One option to do RAII in C in a limited sense is to reserve a buffer
of automatic storage within a function, and then direct allocations to
use that buffer. Typically these region allocators are simple linear
bump the pointer schemes with no individual object deallocation, so
one has to tune the buffer size to the expected input. There's
commonly a reset that "frees" all the objects at once. You have to
take care of the alignment yourself, either manually using 'alignof
(type)' or 'ALIGN_MAX', but at the end of the function, the automatic
storage goes away and you can skip any deallocation that you would
have had to do.

It can be useful in functions that build some kind of precomputed
state that you want to optimize for smaller problems, but default back
to the standard allocator for bigger ones. An example could be
building a partial match table for string searching using the Knuth-
Morris-Pratt algorithm, or the matrix used to compute the Levenshtein
distance. Since automatic allocation is typically fast (bumping the
stack pointer) when compared to what happens internally using 'malloc'
and friends, it's possible to leverage automatic storage to squeeze
out a little more performance out of your allocations in these kinds
of algorithms.

Best regards,
John D.
 
Reply With Quote
 
James Kuyper
Guest
Posts: n/a
 
      10-26-2012
On 10/26/2012 09:51 AM, James Kuyper wrote:
....
> ... That could only be objects with automatic storage duration


automatic => allocated

> that are free()d inside the exit handler. ...


 
Reply With Quote
 
ImpalerCore
Guest
Posts: n/a
 
      10-27-2012
On Oct 26, 7:42*pm, Paavo Helde <(E-Mail Removed)> wrote:
> ImpalerCore <(E-Mail Removed)> wrote in news:fb6dea90-99b9-4ac5-88b0-
> (E-Mail Removed):
>
>
>
> > One option to do RAII in C in a limited sense is to reserve a buffer
> > of automatic storage within a function, and then direct allocations to
> > use that buffer.

>
> This again assumes RAII is only about releasing memory. If this was the
> case, one could just add a Boehm garbage collector to the program and
> forget about all those issues. In reality, RAII in C++ is equivalently
> important for mutex unlocking, file handle closing, ending the sandclock
> mode of the mouse cursor, etc, etc.


Originally RAII was designed to handle memory cleanup in the presence
of exceptions, as it's pretty much a necessity to write exception safe
code in C++. I would say that when people saw how good RAII was in
memory cleanup that it was applied to other resource cleanup as well.
Hence the phrase "limited sense", as C does not provide language
support of anything resembling destructors.

> > Typically these region allocators are simple linear
> > bump the pointer schemes with no individual object deallocation, so
> > one has to tune the buffer size to the expected input. *There's
> > commonly a reset that "frees" all the objects at once. *You have to
> > take care of the alignment yourself, either manually using 'alignof
> > (type)' or 'ALIGN_MAX', but at the end of the function, the automatic
> > storage goes away and you can skip any deallocation that you would
> > have had to do.

>
> For stack allocations there is the alloca() function, and also C99 VLA-s,
> no need to reinvent the wheel. Or is this something different you are
> talking about?
>
> A general problem with using variable amounts of stack memory is that the
> total amount of the stack space is quite small and implementation-
> dependent and a stack overflow yields UB without any standard detection
> or interception means. So writing a robust program with variable-size
> stack allocations is pretty hard.


The difference is that this mechanism is a "fixed" stack allocation.
One issue is that alloca is not standard, and C99 VLAs do not apply to
C90 environments, which limit the scope of environments they can be
applied. While the 'region' technique has the same recursion issues
that alloca and C99 VLAs have, the stack size reserved to an algorithm
that needs to allocate memory is fixed. That means that passing big
input doesn't result in a big alloca or VLA resize that blows up the
stack.

Here's an excerpt from my region allocator.

\code
struct c_region
{
/*! \brief The start of the memory buffer. */
unsigned char* start;

/*! \brief The end of the memory buffer. */
unsigned char* end;

/*! \brief The next available address to allocate from in the
region. */
unsigned char* current;
};

void c_region_initialize( struct c_region* region, void* buffer,
size_t size )
{
c_return_if_fail( region != NULL );
c_return_if_fail( buffer != NULL );

region->start = buffer;
region->end = (unsigned char*)buffer + size;
region->current = buffer;

C_REGION_INVARIANT( region );
}

void* c_region_allocate( struct c_region* region,
size_t size,
size_t alignment )
{
unsigned char* aligned_p;

c_return_value_if_fail( region != NULL, NULL );
C_REGION_INVARIANT( region );

size = size == 0 ? 1 : size;
alignment = alignment == 0 ?
ALIGN_MAX :
c_round_up_to_power_of_two( alignment );
c_assert( c_is_power_of_two( alignment ) );

aligned_p = c_align_up( region->current, alignment );
c_assert( c_is_aligned_ptr( aligned_p, alignment ) );

/* To determine whether the region has enough space, one must
factor in the alignment padding as well as the object size. */
if ( aligned_p + size > region->end ) {
return NULL;
}

region->current = aligned_p + size;

C_REGION_INVARIANT( region );

return aligned_p;
}
\endcode

\code
int c_levenshtein( const char* s1, const char* s2 )
{
int distance;

int m, n;
int* proximity_matrix;
struct c_region pm_region;
unsigned char pm_workspace[256];
bool c_malloc_used = false;

c_return_value_if_fail( s1 != NULL, -1 );
c_return_value_if_fail( s2 != NULL, -1 );

m = strlen( s1 );
n = strlen( s2 );

/* If one of the strings is empty "", the edit distance is equal
to the length of the non-empty string. */
if ( m == 0 || n == 0 ) {
return m + n;
}

c_region_initialize( &pm_region, pm_workspace, sizeof
pm_workspace );
proximity_matrix = c_region_allocate( &pm_region,
sizeof (int) * (m+1) * (n+1),
alignof (int) );
if ( proximity_matrix == NULL )
{
proximity_matrix = c_malloc( sizeof (int) * (m+1) * (n+1) );
c_malloc_used = true;
}

if ( proximity_matrix )
{
++m;
++n;

gc_compute_levenshtein_matrix( s1, s2, &m, &n, proximity_matrix );
distance = proximity_matrix[m*n-1];

if ( c_malloc_used ) {
c_free( proximity_matrix );
}
}
else {
distance = -1;
}

return distance;
}
\endcode

The key point to take away from this example is that the size of the
stack used is independent of the size of s1 and s2. While alloca and
VLAs are convenient, they lend themself to a programming style where
it's easy to blow the stack in the presence of a big string. In my
case, I structure the stack allocation so that if it exceeds the
maximum amount I reserved for it (the size of pm_workspace), I return
*NULL*. Adjusting the amount of stack space reserved for
'c_levenshtein' is done by changing the size of 'pm_workspace',
eliminating any manual code to delineate allocations between an alloca
or VLA and malloc; the logic is built into the c_region interface.

One can also leverage a static buffer in the same manner, although one
needs to manually reset the c_region after finished with the workspace
memory.

I hope that adequately explains the benefit of going to the trouble of
using a region allocator.

Best regards,
John D.
 
Reply With Quote
 
Tiib
Guest
Posts: n/a
 
      10-27-2012
On Saturday, 27 October 2012 14:21:17 UTC+3, ImpalerCore wrote:
> On Oct 26, 7:42*pm, Paavo Helde <(E-Mail Removed)> wrote:
> > This again assumes RAII is only about releasing memory. If this was the
> > case, one could just add a Boehm garbage collector to the program and
> > forget about all those issues. In reality, RAII in C++ is equivalently
> > important for mutex unlocking, file handle closing, ending the sandclock
> > mode of the mouse cursor, etc, etc.

>
> Originally RAII was designed to handle memory cleanup in the presence
> of exceptions, as it's pretty much a necessity to write exception safe
> code in C++. I would say that when people saw how good RAII was in
> memory cleanup that it was applied to other resource cleanup as well.
> Hence the phrase "limited sense", as C does not provide language
> support of anything resembling destructors.


RAII idiom was invented by Bjarne Stroustrup. It means "Resource
Acquisition Is Initialisation". He personally named it so originally.
The name is complex to crasp. You should not think that he however
originally meant "Memory Acquisition Is Initialization". Looking his
faq it seems that he knows very well what "resource" is:
http://www.stroustrup.com/glossary.html#Gresource
 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      10-27-2012
On Oct 21, 8:05*am, Juha Nieminen <(E-Mail Removed)> wrote:
> In comp.lang.c++ Nick Keighley <(E-Mail Removed)> wrote:


> >> > However, in the case of C the "simplicity" is not actually a factor
> >> > that helps writing simple programs. On the contrary, the "simplicity"
> >> > of the language is actually a limiting factor. Rather than help, it
> >> > impedes the writing of simple programs,

>
> > I simply disagree

>
> You are entitled to. However, do you have an actual *argument* against
> what I said, other than "I simply disagree" and "for instance?"


well I thought you were the one making the large claim; that a
language that is "simple" because it's small and reasonably easy to
learn isn't "simple" in its application. Obviously you can write
horrible programs in any language. C (or reasonably well written C) is
usually quite transparent.

I have to admit these days I write C++. Even for noddy little programs
(which I probably should be using a script for). std::vector,
std::string just being too good to pass over.

> In things like Lisp, Haskell and Scheme, the simplicity of the language
> usually translates to the code itself becoming simple and elegant.


probably never became good enough with any of these for it to kick. I
quite like scheme but it never seemed to end up being really "simple".
But I accept that's my fault.

> Often
> you can express in a couple of lines what requires dozens of lines in C++
> and hundreds of lines in C. And those two lines are not obfuscated beyond
> comprehension, but (when you know the language) are clear, simple and
> elegant.
>
> There are several reasons for this, but one of the most important ones is
> that the language doesn't burden the programmer with things like memory
> management.


and garbage collection has its own problems

> Many C advocates try to ride on this concept of "simplicity", but what
> they are doing is a glaring fallacy of equivocation. They are (perhaps
> deliberately) confusing the brevity of the language specification with
> the concept of "simplicity" when talking about programming languages.
>
> Just because the language specification is relatively short (and it's
> relatively easy to make a compiler for it) doesn't make the language
> *simple*. This is a different kind of "simplicity". A kind that does
> *not* help the programmer, but on the contrary is a limitation.


 
Reply With Quote
 
Nick Keighley
Guest
Posts: n/a
 
      10-27-2012
On Oct 21, 8:32*am, Juha Nieminen <(E-Mail Removed)> wrote:
> In comp.lang.c++ Les Cargill <(E-Mail Removed)> wrote:


> > No, I think the "simplicity" of 'C' is more akin to exploiting
> > the representation of data itself. Knowing how stuff is laid out
> > in memory offers some measure of relief from some of the bureaucracy
> > of some systems.

>
> Having the know the exact layout of the data used in the program is a
> really niche use case. Hardly something relevant to the average program.


besides it isn't true anyway. You have to know quite a bit about your
compiler to know how data is laid out. In principle it can change at
the drop of an optimisation flag

> Regardless, since we are comparing C to C++, and the argument is that
> C is "simpler" (and therefore many people prefer to use it), what makes
> to you think that it's not possible (or even harder) to know the exact
> memory layout of the data in a C++ program?
>
> If, for example, you need for some reason to define a struct in some
> precise manner, there's nothing in C++ stopping you from doing that.
> There's nothing that C can offer in this regard that's not possible
> in C++.
>
> (And before you argue "well, if you are restricting your C++ program
> to what C already does, why use C++ at all?" the answer is: To make
> the *rest* of the program, ie. the parts that do *not* need that kind
> of low-level tinkering, much easier.)


yes I've seen programs with C down in the bowels doing lost of bit
banging (near signal processing) but this was all embedded in classes
that hid the nasty stuff from the rest of the program.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Array question - How dynamic is dynamic? Ruby Student Ruby 4 04-09-2009 12:59 PM
Dynamic control on aspx page, dynamic location Chris Thunell ASP .Net 3 07-21-2004 04:52 PM
VPN between 2 Cisco routers (1 static, 1 dynamic) with access from stat --> dynamic over ISDN Hans-Peter Walter Cisco 3 01-21-2004 02:12 PM
Does Pix or cisco router support dynamic-to-dynamic IPSec VPN? c Cisco 2 01-13-2004 01:53 AM
Re: Dynamic Table with Dynamic LinkButtons Rick Glos ASP .Net 0 07-08-2003 01:09 PM



Advertisments