Zero-size array as struct member

J

joe

Öö Tiib said:
No. boost::array does usually allocate together with struct that
contains it. It is like any usual non dynamic array. Since i used
boost::make_shared<> in my example it did exactly one allocation
(allocating room both for svrlist and for shared_ptr pointing at it at
once).


No. My argument is that there is always a way to write it in C++.

The only way to get struct hack characteristics in C++ is to use the
struct hack (some version of it). C++ provides no alternative nor does it
recognize the technique. It is deficient in that regard.
That struct hack is there since C provides you no much other ways.

C99 standardizes the technique and therefor provides the only way, while
C++ has a hole in the spec for the capabilities of the struct hack.
If the
already existing things do not suit you then fine, but that hack is
ugly don't you see?

It doesn't matter how ugly it is, if it is the correct tool for the job.
In C++, when you need the struct hack, you can either build the right
thing, using the struct hack, even though it is ugly, or you can build
the wrong thing that is pretty using some inappropriate C++
construct/abstraction. Correctness vs. cosmetics.
 
J

joe

Juha said:
Öö Tiib said:
No. boost::array does usually allocate together with struct that
contains it. It is like any usual non dynamic array. Since i used
boost::make_shared<> in my example it did exactly one allocation
(allocating room both for svrlist and for shared_ptr pointing at it
at once).

There's a failure at communication here. You are creating an array of
struct objects. That's not the issue here. The issue is the array
which is inside the struct, as its last member, which size is
determined at runtime (rather than at compile time).
No. My argument is that there is always a way to write it in C++.

There's always a way to write *what* in C++?
That
struct hack is there since C provides you no much other ways.

Of course C provides you other ways. You could do this in C:

struct MyStruct
{
int size;
int* array; // instead of int array[0];
};

That's not contiguous. Entirely different animal. You may be able to
replace the above with the struct hack, but you can't replace the struct
hack with the above, for it would be fundamentatlly incorrect to do so.
 
J

joe

Bo said:
Juha said:
Of course C provides you other ways. You could do this in C:

struct MyStruct
{
int size;
int* array; // instead of int array[0];
};

However, now you need to allocate the array separately. Thus you
end
up with two allocations: One for the struct instantiation itself,
and another for the array inside it. The struct hack avoids the
latter allocation by making the array be in the same memory block
as the
struct instantiation itself.

In C++ you can use std::vector instead of int*, but that changes
nothing (it only makes it easier and safer to use, but it still
causes the same amount of memory allocations to be performed).

No, in C++ you would use a std::vector in place of the MyStruct, not
in place of the buffer pointer. That is what people have been trying
to tell you here.

You are missing the fact that the above array-looking struct is just an
example and that the struct could and probably will have other members
and represent some application-specific thing rather than simply an
array. Someone posted an example of a Message struct that should clear
things up a bit for you.
C and C++ are two different languages, and you do things differently.

Except for the struct hack. Well, in C99 its no longer a hack, but in C++
one has no alternative but to use the traditional hack.
 
L

lucdanton

[...]
It doesn't matter how ugly it is, if it is the correct tool for the job.
In C++, when you need the struct hack, you can either build the right
thing, using the struct hack, even though it is ugly, or you can build
the wrong thing that is pretty using some inappropriate C++
construct/abstraction. Correctness vs. cosmetics.

But when does one need the struct hack? If you need a variable-sized
member but don't want to pay the cost for double indirection, the
idiomatic C++ answer can *still* be std::vector: after all, most
operations are applied on ranges (iterator pairs), not containers. So
you pass iterators by value anyway, not containers by reference (which
is where you may pay an additional indirection depending on QoI). If
you're working with an API that expects containers, it's (IMO) a bad
design on the part of the designers: the concern of container classes
is to manage the lifetimes of their elements, passing container
instances or references to them around is not that as innocent as
working with views (i.e. iterators in C++) to their elements.

In fact, even in C99, if you have a function of the form
ret_t some_func(hack_t *inst);

it could be written in the form:
ret_t some_func(elt_t *data, size_t count);

After all you can only have one flexible member of known type.
Of course you can then argue that the new function expects *any* sort
of element range, where perhaps you wanted a module-like interface,
where different hack_t objects not only had different flexible member
length (i.e. the count argument), but different interpretation of it.
A classical use of C99 flexible members for encapsulation and/or
opaque types.

Then use interfaces in C++. The "problem" of double indirection is
still likely to be here depending on QoI, but really, when you use the
struct hack/flexible members in C for encapsulation/data hiding (as
opposed to a dynamic size only) you're really implementing some sort
of dynamic dispatch and so you *have* to pay some amount of
indirection; in C++ might as well let the implementation deal with it
with the explicifit language facilities instead of succumbing to
premature optimization. The implementation is (with all due respect)
more likely to cache or otherwise deal with the double indirection.

If you're wondering I do not find the struct hack/flexible member
'ugly'. I make use of it when writing C99 and am very glad that it was
made part of the standard.
 
G

gwowen

[...]
It doesn't matter how ugly it is, if it is the correct tool for the job..
In C++, when you need the struct hack, you can either build the right
thing, using the struct hack, even though it is ugly, or you can build
the wrong thing that is pretty using some inappropriate C++
construct/abstraction. Correctness vs. cosmetics.

But when does one need the struct hack? If you need a variable-sized
member but don't want to pay the cost for double indirection,

The "cost of double indirection" is not the same as "the performance
hit of any extra malloc() and and an extra dereference". Double
indirection means non-contiguous. Sometimes you need a simple,
*contiguous* structure of variable size. In particular, inter-process/
inter-language operations are often greatly simplified by using such
structures.

If you can't see any applications where contiguous data structures are
important, you will never be convinced that std::vector isn't the
answer. If you can, you will.
 
L

lucdanton

[...]
In particular, inter-process/
inter-language operations are often greatly simplified by using such
structures.

If you can't see any applications where contiguous data structures are
important, you will never be convinced that std::vector isn't the
answer.  If you can, you will.

Those are nice examples, thanks. For those specific domains I'd
probably write a class with the variable aspect of it tucked away in a
container (idiomatic C++), and write serializing and deserializing
operations that pack the representation on a contiguous strip. Well,
assuming I have the need for the class on the C++ side, just the
serialization operations with containers arguments if only an
interface is needed.

If I don't have the luxury of preparing a new representation each time
I serialize, then I could emulate the struct hack by writing a class
that only pass around the contiguous strip (typically a
std::vector<unsigned char>) with an interface if that's important.
Obviously more painful than C99 (or C90 with extensions) since this
will probably require all that offsetof magic; especially tedious if
the types on the strip are not trivial (but then that comes from C++,
not C). By this point I'm convinced that flexible members would be
neat in C++, even if it required trivialness like (restricted) unions
do (well, POD-ness) :) although to be honest I wouldn't give it much
priority (still higher than VLA's though!).
 
J

Juha Nieminen

joe said:
There is no alternative to the struct hack in C++.

However, C++ offers you tools to abstract away the struct hack (ie.
behind easier-to-use public interfaces of classes and/or via using a
custom memory allocator), making the usage easier, cleaner and safer.
 
J

Juha Nieminen

joe said:
Before you can use a tool, you must understand what its purpose is. The
struct hack is not a performance optimization. You have categorized it
incorrectly.

Well, let's say that the only advantage I can think of with struct hacks
is efficiency (they consume less memory and are faster to allocate than
the "normal" solution of allocating the struct and the array separately).

I can't think of any significant advantages. If memory usage efficiency
is not an issue, why would I use the struct hack for anything? There are
much cleaner, easier and safer ways of achieving the same result in cases
where efficiency is not an issue.
 
H

Helge Kruse

Juha Nieminen said:
Well, let's say that the only advantage I can think of with struct hacks
is efficiency (they consume less memory and are faster to allocate than
the "normal" solution of allocating the struct and the array separately).

I can't think of any significant advantages. If memory usage efficiency
is not an issue, why would I use the struct hack for anything?
Marshalling can be an issue. Think of passing the struct from one process to
another using shared memory. When you have the array in a stl vector, you
have additional costs. The same applies to inter process communication using
any socket layer like TCP.

Helge
 
V

Vladimir Jovic

Helge said:
Marshalling can be an issue. Think of passing the struct from one process to
another using shared memory. When you have the array in a stl vector, you
have additional costs. The same applies to inter process communication using
any socket layer like TCP.

But in that case, why use hacks of this type? For IPC, you can not pass
pointers. There are other mechanisms, therefore there are no needs for
such hacks.
 
H

Helge Kruse

Vladimir Jovic said:
But in that case, why use hacks of this type? For IPC, you can not pass
pointers. There are other mechanisms, therefore there are no needs for
such hacks.

What pointers? The OP wrote this:

struct SvrList{
unsigned int uNum;
GameSvr svr[0]; //line A
};
 
G

gwowen

I can't think of any significant advantages.

Sometime contiguity is needed, or very, very helpful, to the extent
that is a significant. The fact that you do not believe this has no
bearing on the fact that it is true.
 
V

Vladimir Jovic

Helge said:
Vladimir Jovic said:
But in that case, why use hacks of this type? For IPC, you can not pass
pointers. There are other mechanisms, therefore there are no needs for
such hacks.

What pointers? The OP wrote this:

struct SvrList{
unsigned int uNum;
GameSvr svr[0]; //line A
};

You switched to interprocess communication. For that, this hack should
not be used. For IPC (at least on linux, don't know how it is done on
other platforms), it is done this way:
http://linux.die.net/man/7/mq_overview
http://linux.die.net/man/2/mmap
http://linux.die.net/man/2/shmget
 
H

Helge Kruse

Vladimir Jovic said:
Helge said:
Vladimir Jovic said:
Helge Kruse wrote:

Well, let's say that the only advantage I can think of with struct
hacks
is efficiency (they consume less memory and are faster to allocate
than
the "normal" solution of allocating the struct and the array
separately).

I can't think of any significant advantages. If memory usage
efficiency
is not an issue, why would I use the struct hack for anything?
Marshalling can be an issue. Think of passing the struct from one
process to another using shared memory. When you have the array in a
stl vector, you have additional costs. The same applies to inter
process communication using any socket layer like TCP.
But in that case, why use hacks of this type? For IPC, you can not pass
pointers. There are other mechanisms, therefore there are no needs for
such hacks.

What pointers? The OP wrote this:

struct SvrList{
unsigned int uNum;
GameSvr svr[0]; //line A
};

You switched to interprocess communication. For that, this hack should not
be used. For IPC (at least on linux, don't know how it is done on other
platforms), it is done this way:
http://linux.die.net/man/7/mq_overview
http://linux.die.net/man/2/mmap
http://linux.die.net/man/2/shmget

Thanks for these (os-dependent) examples. These functions like msgsnd expect
a pointer to _one_ object. That fits perfect to the struct show above. The
GameSvr array is embedded in the SrvList object. This avoids pointers.
When you have a pointer to an addtional chunk of data, like std::vector
implementations use, instead of an embedded object you have to build an
message object, compose a memory layout and than you are ready to pass it to
msgsend. Finally you drop the temporary object.
 
J

joe

gwowen said:
[...]
It doesn't matter how ugly it is, if it is the correct tool for the
job. In C++, when you need the struct hack, you can either build
the right thing, using the struct hack, even though it is ugly, or
you can build the wrong thing that is pretty using some
inappropriate C++ construct/abstraction. Correctness vs. cosmetics.

But when does one need the struct hack? If you need a variable-sized
member but don't want to pay the cost for double indirection,

Double
indirection means non-contiguous. Sometimes you need a simple,
*contiguous* structure of variable size. In particular,
inter-process/ inter-language operations are often greatly simplified
by using such structures.


It's amazing how many times that can be said and no one hears it.
If you can't see any applications where contiguous data structures are
important, you will never be convinced that std::vector isn't the
answer.

IOW, "can't see the forrest for the trees"?
 
J

joe

lucdanton said:
[...]
In particular, inter-process/
inter-language operations are often greatly simplified by using such
structures.

If you can't see any applications where contiguous data structures
are important, you will never be convinced that std::vector isn't the
answer. If you can, you will.

Those are nice examples, thanks. For those specific domains I'd
probably write a class with the variable aspect of it tucked away in a
container (idiomatic C++), and write serializing and deserializing
operations that pack the representation on a contiguous strip.

That, is what C++ "forces" you to do because it lacks formalization of
the struct hack. I'm not so sure that lack of struct hack standardization
in C++ or avoidance of standardizing it isn't because of a fundamental
incorrrectness of C++'s design.
 
J

joe

Juha said:
However, C++ offers you tools to abstract away the struct hack (ie.
behind easier-to-use public interfaces of classes and/or via using a
custom memory allocator), making the usage easier, cleaner and safer.

Wrong. That is something different. Apples and oranges again, and
actually, they're not even both fruits!
 
J

joe

Juha said:
Well, let's say that the only advantage I can think of with struct
hacks is efficiency (they consume less memory and are faster to
allocate than the "normal" solution of allocating the struct and the
array separately).

It's obvious that you do think that.
I can't think of any significant advantages. If memory usage
efficiency is not an issue, why would I use the struct hack for
anything?

Go back and reread the other posts where it has already been explained.
There are much cleaner, easier and safer ways of achieving
the same result in cases where efficiency is not an issue.

No, there really isn't. It isn't an issue of the endpoint, it's an issue
of the means by which to achieve it, for the topic is of a programming
technique, and of facilitation of programming. It is not an issue of "oh
well, it can be done in assembly language too!". That you personally
don't care to have the tool in your toolbox is fine and dandy. I, OTOH,
hold it as one of my favorite tools (not that it gets a lot of use, but
that I find it very important to have when I need it).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,145
Messages
2,570,826
Members
47,371
Latest member
Brkaa

Latest Threads

Top