Re: C++ equivalent of C VLAs and subsequent issues with offsetof
Carl Barron wrote:
In article <f4afpb$kj2$1@news.Stanford.EDU>, Seungbeom Kim
<musiphil@bawi.org> wrote:
How likely is it for the next version of C++ to incorporate such a
feature of C99, of the last member of a struct having an incomplete
array type?
struct foo
{
int len;
double data[];
};
what is sizeof(foo)?
offsetof(foo, data).
Quoted from C99 6.7.2.1/16:
"As a special case, the last element of a structure with more than one
named member may have an incomplete array type; this is called a
flexible array member. With two exceptions, the flexible array member is
ignored.
First, the size of the structure shall be equal to the offset of the
last element of an otherwise identical structure that replaces the
flexible array member with an array of unspecified length.
Second, when a . (or ->) operator has a left operand that is (a pointer
to) a structure with a flexible array member and the right operand names
that member, it behaves as if that member were replaced with the longest
array (with the same element type) that would not make the structure
larger than the object being accessed; the offset of the array shall
remain that of the flexible array member, even if this would differ from
that of the replacement array. If this array would have no elements, it
behaves as if it had one element but the behavior is undefined if any
attempt is made to access that element or to generate a pointer one past
it."
what does new foo; produce? or bet yet what
does new foo[10] produce?
What should probably be done is to create an object without the 'data'
member but with possible padding before it. For example, if sizeof(int)
== 4 and alignof(double) == 8, then each foo object created would be of
8 bytes, with 4 bytes of int and 4 bytes of padding. This ensures the
correct alignment of the 'data' member, as long as sufficient storage is
allocated.
what is it going to do with
struct bar
{
int n;
std::string lines[];
}; ?
Under the same principle, new bar or new bar[] should not create any
'lines' member. This type can be used in the following way:
struct bar
{
int n;
std::string lines[];
static bar* create(int n);
static void destroy(bar* p);
};
bar* bar::create(int n)
{
std::size_t size = sizeof(bar) + n * sizeof(std::string);
bar* p = static_cast<bar*>(std::malloc(size));
if (p == 0) throw std::bad_alloc();
p->n = n;
try {
std::uninitialized_fill_n(p->lines, n, std::string());
}
catch (...) {
std::free(p);
throw;
}
return p;
}
void bar::destroy(bar* p)
{
for (std::string* i = p; i != p + n; ++i) i->~std::string();
std::free(p);
}
bar* p = bar::create(2);
// Now p points to something as good as
// struct { int n; std::string lines[2]; }
std::cin >> p->lines[0] >> p->lines[1];
std::cout << p->lines[0] << p->lines[1];
bar::destroy(p);
(It would be cleaner to use the allocator interface, but the current
allocator interface doesn't seem to support such a usage easily, so I
had to resort to the C-style malloc and free.)
I'd say that this is not likely, the apparent waste of a double
above makes the answers obvious ,even if it is useless, and your
special allocation functions only need to forget about the extra
declared entry, assuming the c'ism works, all is well, little or
nothing is gained by allowing empty array declarations in structs.
The gains are:
* alignment taken care of by the compiler, and
* convenient access to the array member
if you want the whole structure itself to be dynamically allocated and
you don't want an extra dynamic allocation just for the array, as in
shared representations such as reference-counted strings, as suggested
by the OP.
Without the support for flexible array members, how do you figure out
the offset of the array member within the structure? I think there can
be some hacks, but it would be very hard to avoid the realm of UB
without the help of some magic from the compiler.
Probably it's not going to be used by a lot of application programmers,
but it can be of certain value to library implementors. Or all the gory
details I suggested above could made into a library facility so that it
could be used conveniently by anyone in need of such a feature.
--
Seungbeom Kim
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]