By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
454,134 Members | 1,195 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 454,134 IT Pros & Developers. It's quick & easy.

Smart pointer for arrays of structs?

P: n/a
Hi,

I have some data which is stored as plain old C structures. Until now I've
had arrays of these structs on stack but due to stack overrun I need to move
these to heap.
I've been trying out some smart pointers to help but so far the
implementation I've been dealing with has had problems with [] operator
since it could conflict when using the same class with "unsigned char".

Do you have any recommendations for smart pointers able to work with arrays?

I would need something like:

ptr = (new or malloc) MY_STRUCT [16];

ptr[i].member

Thanks.

-- Henrik
Dec 26 '06 #1
Share this Question
Share on Google+
12 Replies


P: n/a
Henrik Goldman wrote:
Hi,

I have some data which is stored as plain old C structures. Until now I've
had arrays of these structs on stack but due to stack overrun I need to move
these to heap.
I've been trying out some smart pointers to help but so far the
implementation I've been dealing with has had problems with [] operator
since it could conflict when using the same class with "unsigned char".

Do you have any recommendations for smart pointers able to work with arrays?

I would need something like:

ptr = (new or malloc) MY_STRUCT [16];

ptr[i].member
What is wrong with std::vector ?
Dec 26 '06 #2

P: n/a
>
What is wrong with std::vector ?
I forgot to mention that it's a requirement that the data needs to be
accessible from external C functions. For this reason it needs to be
serialized just like an ordinary array.

-- Henrik
Dec 26 '06 #3

P: n/a
"Henrik Goldman" <he************@mail.tele.dkwrote in message
news:45*********************@dread11.news.tele.dk. ..

What is wrong with std::vector ?

I forgot to mention that it's a requirement that the data needs to be
accessible from external C functions. For this reason it needs to be
serialized just like an ordinary array.

-- Henrik
std::vector fits the bill for that.
http://www.parashift.com/c++-faq-lit....html#faq-34.3
vector stores it's memory contiguous

Dec 26 '06 #4

P: n/a

Henrik Goldman wrote:

What is wrong with std::vector ?

I forgot to mention that it's a requirement that the data needs to be
accessible from external C functions. For this reason it needs to be
serialized just like an ordinary array.

-- Henrik
The std::vector is then perfect for the job. Not only are its elements
organized in contiguous memory and dynamic, its also much easier to
overload a global op<< to stream/serialize the data.

Show me code with a primitive array, and i'll show you a std::vector
that does the same but better, and then some. And that includes
performance.

Dec 26 '06 #5

P: n/a
Thank you Gianni, Jim, Peter, for your answers.

It seems to be a good choice. It certainly saved me from a day of work
trying to get a smart pointer class working to do the same job.

The way I use it is:

vector <mytypev;

v.resize(nElements);
and then
memset(&v[0], 0, sizeof(mytype) * v.size());

It's too bad I cannot do all the initialization at once. However the data
needs to be zero initialized and have a certain size. All in all it does
save me from some work so it's a cheap price to pay.

-- Henrik
Dec 26 '06 #6

P: n/a

Henrik Goldman wrote in message
<45*********************@dread11.news.tele.dk>.. .
>Thank you Gianni, Jim, Peter, for your answers.

It seems to be a good choice. It certainly saved me from a day of work
trying to get a smart pointer class working to do the same job.
The way I use it is:

vector <mytypev;

v.resize(nElements);
and then
memset(&v[0], 0, sizeof(mytype) * v.size());

It's too bad I cannot do all the initialization at once. However the data
needs to be zero initialized and have a certain size. All in all it does
save me from some work so it's a cheap price to pay.
--- Henrik
std::size_t nElements( 100 );
std::vector <mytypev( nElements, mytype(0) );

--
Bob R
POVrookie
Dec 26 '06 #7

P: n/a

Henrik Goldman wrote:
Thank you Gianni, Jim, Peter, for your answers.

It seems to be a good choice. It certainly saved me from a day of work
trying to get a smart pointer class working to do the same job.

The way I use it is:

vector <mytypev;

v.resize(nElements);
and then
memset(&v[0], 0, sizeof(mytype) * v.size());

It's too bad I cannot do all the initialization at once. However the data
needs to be zero initialized and have a certain size. All in all it does
save me from some work so it's a cheap price to pay.

-- Henrik
Oh yes you can. In more ways than one.
There is no need to use memset, let a ctor and copy-ctor do the work
for you.

#include <vector>

template< typename T >
class mytype
{
T t;
public:
mytype() : t() { }
mytype(const T& r_t) : t(r_t) { }
};

int main()
{
std::vector< mytype< double instance(1000); // same as
instance(1000, 0.0);
std::vector< mytype< double another(1000, 11.1);
std::vector< std::string vstrings(1000, "default string");
std::vector< int vn(1000, 99);
}

The first creates an instance of a std::vector with 1000 elements all
initialized to 0.0 (by def ctor)
The second initializes 1000 elements with a value of 11.1 (using
parametized ctor)
The third initializes 1000 std::strings with the same default.
The fourth has 1000 integers set to 99.

The only requirement is that the element-type be copyable and
assignable (op=). In the case involving the class above, mytype's
compiler-generated copy ctor and assignment operator fits the bill. In
the event your class doesn't have a compiler-generated ctor or op=,
make them.

Dec 26 '06 #8

P: n/a
Henrik Goldman wrote:
>What is wrong with std::vector ?

I forgot to mention that it's a requirement that the data needs to be
accessible from external C functions. For this reason it needs to be
serialized just like an ordinary array.
Again, what's wrong with std::vector? :)

std::vector<Tvec = ...;

extern "C" T *GetCArray()
{
return &vec.front();
}

--
Clark S. Cox III
cl*******@gmail.com
Dec 27 '06 #9

P: n/a

Henrik Goldman wrote:
>
vector <mytypev;

v.resize(nElements);
and then
memset(&v[0], 0, sizeof(mytype) * v.size());

It's too bad I cannot do all the initialization at once. However the data
needs to be zero initialized and have a certain size. All in all it does
save me from some work so it's a cheap price to pay.
If mytype is a class then its constructor will automatically be called.

If mytype is a C struct that needs to be used with C headers too (thus
you can't give it any constructors), then you can still do it using a
0-initialised element to constructor your vector or call resize. You
just have to create one such struct and use it to initialise all the
other members.

Note that you could use a "static" instance of one.

Beware, by the way, that &v[0] or &v.front() is undefined behaviour if
v is an empty vector, so you should check for this and probably return
a NULL pointer when that is the case.

Dec 27 '06 #10

P: n/a
If mytype is a C struct that needs to be used with C headers too (thus
you can't give it any constructors), then you can still do it using a
0-initialised element to constructor your vector or call resize. You
just have to create one such struct and use it to initialise all the
other members.
Yes in my case it's a C struct.
I don't really like your suggestion about using a preinitialized value
though. It requires even more code then other proposed solutions.
Note that you could use a "static" instance of one.
That is really not a good idea in my case since the code is used among
different projects and modules. It only makes it harder to understand.
Beware, by the way, that &v[0] or &v.front() is undefined behaviour if
v is an empty vector, so you should check for this and probably return
a NULL pointer when that is the case.
This is not the case for me fortunatly. In those places where I need it it
has been resize()'d in the constructor prior to any use.

Thanks.

-- Henrik
Dec 28 '06 #11

P: n/a

Henrik Goldman wrote:
Note that you could use a "static" instance of one.

That is really not a good idea in my case since the code is used among
different projects and modules. It only makes it harder to understand.
It doesn't really need to be static, a const global will do. It should
be initialised in one module though. Although globals are normally
evil, if it's const it is less evil.

const mytype zero_my_type = { 0, 0, 0, 0 }; // etc

then my_type_vec.resize( 50, zero_my_type );

If you prefer you can scope the instance and expose the function but
you really haven't gained a lot.
Beware, by the way, that &v[0] or &v.front() is undefined behaviour if
v is an empty vector, so you should check for this and probably return
a NULL pointer when that is the case.

This is not the case for me fortunatly. In those places where I need it it
has been resize()'d in the constructor prior to any use.
I have wrapper "buffer" classes that will wrap arrays or vectors and it
also has a begin() and end() which are guaranteed to be pointers. (I
have two such classes, one for const and one for non-const). buffer is
fairly trivial to write and looks something like this:

template < typename T >
class buffer
{
T * itsData;
size_t itsSize;
public:
buffer( T* d, size_t sz ) : itsData( d ), itsSize( sz ) {}

buffer( vector< T & vec )
: itsData( vec.empty() ? 0 : &vec[0] ),
itsSize( vec.size() )
{
}

buffer() : itsData( 0 ), itsSize( 0 )
{
}

buffer( T* first, T* last ) : itsData( first ), itsSize( last -
first )
{
}

T* begin() const { return itsData; }
T* end() const { return itsData + itsSize; }
bool empty() const { return itsSize == 0; }
size_t size() const { return itsSize; }
};

Define const_buffer exactly the same but with const T* pointers and
const std::vector<T& and add this constructor

const_buffer( const buffer<T& nc_buf ) : itsData( nc_buf.begin()
), itsSize( nc_buf.size() )
{
}

Note that these classes do not take ownership of the buffer so there is
no memory handling issue. You might be surprised that begin() and end()
are const methods even in buffer. They are because you cannot modify
the pointers themselves, only what they point to. The class is
non-mutable (cannot be changed) other than assigning it to another
instance. Note that its constructors that take one parameter are
purposely non-explicit.

Now with a vector that might be empty and passing it to a functino that
takes a pointer and size that might be empty you can always pass in

buffer( theVec ).begin() (or const_buffer( theVec ).begin() if
appropriate)

Dec 28 '06 #12

P: n/a
Henrik Goldman wrote:
Thank you Gianni, Jim, Peter, for your answers.

It seems to be a good choice. It certainly saved me from a day of work
trying to get a smart pointer class working to do the same job.

The way I use it is:

vector <mytypev;

v.resize(nElements);
and then
memset(&v[0], 0, sizeof(mytype) * v.size());

It's too bad I cannot do all the initialization at once. However the data
needs to be zero initialized and have a certain size.
static const mytype t;
vector<mytype v;
v.resize(nElements, t);
--
Clark S. Cox III
cl*******@gmail.com
Dec 28 '06 #13

This discussion thread is closed

Replies have been disabled for this discussion.