memset on structs with non-PODs

P

Patrick Kowalzick

Dear all,

I have an existing piece of code with a struct with some PODs.

struct A
{
int x;
int y;
};

This struct is created somewhere and initialized via a memset.

A a;
memset(&a,0,sizeof(A));

Now I want to extend the structure with an object, e.g a vector:

struct A
{
int x;
int y;
std::vector<int> z;
};

The sequence

A a;
memset(&a,0,sizeof(A));

would be fatal now, because I overwrite the instanciated vector a.z.


In reality the struct is very huge with a bunch of PODs inside, so using a
ctor would be possible, but quite a lot of work. (I am also scared to miss
something). How would you proceed to avoid the devastating memset?


I thought of kind of

struct A
{
int x;
int y;
int no_memsetbeyond_this_point;
std::vector<int> z;
};

and

A a;
memset(&a,0,&a.no_memsetbeyond_this_point-&a);

It is not really nice, but I have to avoid as much code-rework as possible
for the moment.

Kind regards,
Patrick
 
A

Alf P. Steinbach

* Patrick Kowalzick:
Dear all,

I have an existing piece of code with a struct with some PODs.

struct A
{
int x;
int y;
};

This struct is created somewhere and initialized via a memset.

A a;
memset(&a,0,sizeof(A));

Now I want to extend the structure with an object, e.g a vector:

struct A
{
int x;
int y;
std::vector<int> z;
};

When you have public non-POD members you need to redesign.

The sequence

A a;
memset(&a,0,sizeof(A));

would be fatal now, because I overwrite the instanciated vector a.z.


In reality the struct is very huge with a bunch of PODs inside, so using a
ctor would be possible, but quite a lot of work. (I am also scared to miss
something). How would you proceed to avoid the devastating memset?

When you a "very huge" struct you need to redesign.

But possibly you need to practice that on some smaller test programs
first.

For now, rename the orginal struct to PodA,

struct PodA { ... };

then derive struct A from that,

struct A: PodA
{
A(): PodA() {}
std::vector<int> z;
};

and also check that your compiler supports default-initialization of
POD's (unfortunately some don't).
 
P

Patrick Kowalzick

Hello Alf,
When you have public non-POD members you need to redesign.

Normally I'd never use struct for more complex things :).
When you a "very huge" struct you need to redesign.

Hmm, might be. Lets say very huge in this context is nothing elses than: I
do not want to initialize all the members.
For now, rename the orginal struct to PodA,

struct PodA { ... };

then derive struct A from that,

struct A: PodA
{
A(): PodA() {}
std::vector<int> z;
};

Perfect. Thats a rather good solution. Anyway for this case I will change to

struct PodA
{
PodA() { memset(this,0,sizeof(PodA)); }
...
};

struct A: PodA
{
std::vector<int> z;
};

This is not nice (ok it is ugly), but closer to the original code.
and also check that your compiler supports default-initialization of
POD's (unfortunately some don't).

I can not, as support for different compiliers has to be assured.

Thanks, that's really good solution.

Regards,
Patrick
 
Z

Zara

Dear all,

I have an existing piece of code with a struct with some PODs.

struct A
{
int x;
int y;
};

This struct is created somewhere and initialized via a memset.

A a;
memset(&a,0,sizeof(A));

Now I want to extend the structure with an object, e.g a vector:

struct A
{
int x;
int y;
std::vector<int> z;
};

The sequence

A a;
memset(&a,0,sizeof(A));

would be fatal now, because I overwrite the instanciated vector a.z.
<snip>

You may create a non-virtual base class with only POD data and inherit
from it. In such a way, you could still a memset, but only with thiis
base class.

struct A_
{
int x;
int y;
};

struct A:public A_
{
A() {memset(static_cast<A_ *>(this),0,sizeof(A_);}
std::vector<int> z;
};



Regards,

Zara
 
M

Maxim Yegorushkin

Patrick said:
Dear all,

I have an existing piece of code with a struct with some PODs.

struct A
{
int x;
int y;
};

This struct is created somewhere and initialized via a memset.

[]

Overload memset() in the same header where A is declared:

void memset(A*, int, size_t);

Note that this overload won't be called if memset is invoked as:

memset(void*)&a, ...);

A more proper way would be to redesign the code, so that it don't do
memset on A's anymore.
 
M

ma740988

Alf said:
* Patrick Kowalzick:

I have a follow on question to this. Given:

unsigned int const max_id = 5;
unsigned int const max_participants = 5;
struct some_struct
{ int some_param;
some_struct()
: some_param( -1) {}
};

struct some_other_struct
{ int some_var;
int some_size;
unsigned char* ptr;
some_other_struct()
: some_var(-1)
, some_size(-1)
, ptr(0)
{}
};

struct someImportantData {
unsigned int c_style_arr[ max_participants ];
some_struct c_style_arr2[ max_id ] [ max_participants ];
some_other_struct c_style_arr3[ max_participants ];
};


int main()
{
someImportantData sid;
for ( int idx(0); idx < max_participants; ++idx )
{
sid.c_style_arr[ idx ] = idx ;
}
typedef std::vector<unsigned int> UINT_VEC;
UINT_VEC myVec(&sid.c_style_arr[0],
&sid.c_style_arr[max_participants] );

UINT_VEC::iterator end = myVec.end();
for ( UINT_VEC::const_iterator it = myVec.begin(); it != end; ++it )
{
std::cout << *it << std::endl;
}

}

Now going from c_style_arr to a vector is easy (as shown below) .
How would I do the c_style_arr2 and c_style_arr3? Part of the issue
with c_sytle_arr2 is based on the fact that I'm still experimenting
with 2-d vectors.

In any event, thanks in advance.
 
P

Patrick Kowalzick

Hello Maxim,
I have an existing piece of code with a struct with some PODs.

struct A
{
int x;
int y;
};

This struct is created somewhere and initialized via a memset.

[]

Overload memset() in the same header where A is declared:

void memset(A*, int, size_t);

Note that this overload won't be called if memset is invoked as:

memset(void*)&a, ...);

A more proper way would be to redesign the code, so that it don't do
memset on A's anymore.

The memset are not too often, so I kicked them :). But it seems to be a good
idea to overload memset, perhaps I missed one.....

void memset(A*, int, size_t)
{
assert( "Please, please do not use memset for this struct");
}

Hmm, or static_assert? Would something like this work as static assert?

// forward for allowed memsets
template < typename T > class memset_functor
{
public:
void * operator()( T* dest, int c, size_t count )
{
return memset(dest,c,count);
}
};

// forward for disallowed memsets
template <> class memset_functor< A >
{
public:
void * operator()( A *, int, size_t )
{
// STATIC_ASSERTION
}
};

template < typename T >
void * memset( T* dest, int c, size_t count )
{
return memset_functor<T>()(dest,c,count);
}

Looks funny. I will test this towmorrow :)

Regards,
Patrick
 
B

Bo Persson

Patrick Kowalzick said:
Hello Alf,


Normally I'd never use struct for more complex things :).


Hmm, might be. Lets say very huge in this context is nothing elses
than: I do not want to initialize all the members.


Perfect. Thats a rather good solution. Anyway for this case I will
change to

struct PodA
{
PodA() { memset(this,0,sizeof(PodA)); }
...
};


But now you have a constructor, so it's not a POD anymore. :-(

This is not nice (ok it is ugly), but closer to the original code.

It is ugly!


Bo Persson
 
P

Patrick Kowalzick

Hmm, or static_assert? Would something like this work as static assert?
// forward for allowed memsets
template < typename T > class memset_functor
{
public:
void * operator()( T* dest, int c, size_t count )
{
return memset(dest,c,count);
}
};

// forward for disallowed memsets
template <> class memset_functor< A >
{
public:
void * operator()( A *, int, size_t )
{
// STATIC_ASSERTION
}
};

template < typename T >
void * memset( T* dest, int c, size_t count )
{
return memset_functor<T>()(dest,c,count);
}

Looks funny. I will test this towmorrow :)

Ok. I tried it, and it does not work.

The specialization memset_functor< A > will be instanciated, even if there
is no call "memset(A,int,size_t)". Like this the static assertion always
fails.

I use now an easier approach, which works on my compiler, but I am not sure
if it is bullet proof:

template < typename T >
void * memset( TTransferDistlibData2 * dest, T c, size_t count )
{
BOOST_STATIC_ASSERT(FALSE);
return NULL;
}

Calling memset(A,..) fails like this to compile.

Kind regards,
Patrick
 
B

Bo Persson

Patrick Kowalzick said:
Hello Bo,


Hmm, ok. I call it "public class with only PODs inside" :).

Ok, I didn't explain it properly:

If it's not a POD, you cannot use memset() on it.


That was the original problem! :)


Bo Persson
 
P

Patrick Kowalzick

Hello Bo,
Ok, I didn't explain it properly:

If it's not a POD, you cannot use memset() on it.

Why not? I will take a look in the standard, now, but I was quite sure, that
adding a function to POD-struct will not change the memory structure of this
struct. I see no obvious reason, why this should be dangerous.

If it is dangerous there is still the soution Zara suggests...
That was the original problem! :)

Not really. The problem was an inner class, which itself may initialize,
inside a structure which is overwirtten by a memset on the outer struct. The
initialization of the inner class is lost (and even worse the instance might
be invalid).

Kind regards,
Patrick
 
P

Patrick Kowalzick

Hmm, ok. I call it "public class with only PODs inside" :).
Why not? I will take a look in the standard, now, but I was quite sure,
that adding a function to POD-struct will not change the memory structure
of this struct. I see no obvious reason, why this should be dangerous.

I think, a class with a ctor can still be a POD-class. There fore two cites
from the standard:

"(3.9.10) Arithmetic types (3.9.1), enumeration types, pointer types, and
pointer to member types (3.9.2), and cv-qualified versions of these types
(3.9.3) are collectively called scalar types. Scalar types, POD-struct
types, POD-union types (clause 9), arrays of such types and cv-qualified
versions of these types (3.9.3) are collectively called POD types."

"(9.0.4) {...} A POD-struct is an aggregate class that has no non-static
data members of type non-POD-struct, non-POD-union (or array of such types)
or reference, and has no user-defined copy assignment operator and no
user-defined destructor. Similary, a POD-union is an aggregate union that
has no non-static data members of type non-POD-struct, non-POD-union (or
array of such types) or reference, and has no user-defined copy assignment
operator and no user-defined destructor. A POD class is a class that is
either a POD-struct or a POD-union."

I have no other non-POD typed, nor a copy assignment, nor a dtor. So it is
still a POD? But what about a vtable? Might this still be a POD?

Regards,
Patrick
 
P

Patrick Kowalzick

I think, a class with a ctor can still be a POD-class. There fore two
cites from the standard:

Bullshit :).
"(3.9.10) Arithmetic types (3.9.1), enumeration types, pointer types, and
pointer to member types (3.9.2), and cv-qualified versions of these types
(3.9.3) are collectively called scalar types. Scalar types, POD-struct
types, POD-union types (clause 9), arrays of such types and cv-qualified
versions of these types (3.9.3) are collectively called POD types."

"(9.0.4) {...} A POD-struct is an aggregate class that has no non-static
data members of type non-POD-struct, non-POD-union (or array of such
types) or reference, and has no user-defined copy assignment operator and
no user-defined destructor. Similary, a POD-union is an aggregate union
that has no non-static data members of type non-POD-struct, non-POD-union
(or array of such types) or reference, and has no user-defined copy
assignment operator and no user-defined destructor. A POD class is a class
that is either a POD-struct or a POD-union."

I have no other non-POD typed, nor a copy assignment, nor a dtor. So it is
still a POD? But what about a vtable? Might this still be a POD?

"[8.5.1.1] An aggregate is an array or a class (clause 9) with no
user-declared constructors (12.1), no private or protected non-static data
members (clause 11), no base classes (clause 10), and no virtual functions
(10.3)."

And for sure, read the FAQ:
http://www.parashift.com/c++-faq-lite/intrinsic-types.html#faq-26.7

Thanks all a lot for you input in this thread. I hope I got it now.

Kind regards,
Patrick
 
P

Patrick Kowalzick

Hello Alf,
For now, rename the orginal struct to PodA,

struct PodA { ... };

then derive struct A from that,

struct A: PodA
{
A(): PodA() {}
std::vector<int> z;
};

and also check that your compiler supports default-initialization of
POD's (unfortunately some don't).

I checked this. Some of my compilers support default-initialization, some
not :(. This is really sad.

So I use now this here (even if there is a difference to memset in the
result):

struct A_PODs{ ... };

struct A : public A_PODs
{
A()
{
static A_PODs zero_init = { 0 };
// static A_PODs zero_init = { }; // would be enough, but does not
work on all compilers.
*(static_cast< A_PODs * >(this)) = zero_init; // is this safe?
}
};


Kind regards,
Patrick
 

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

Similar Threads


Members online

Forum statistics

Threads
473,768
Messages
2,569,574
Members
45,050
Latest member
AngelS122

Latest Threads

Top